/// <summary> /// Will create tree from given equation string /// </summary> /// <param name="equation">string containing equation</param> /// <returns>valid tree or throw exception</returns> private Tree CreateTree(string equation) { Tree tree = new Tree(); // if is equation inside brackets -> remove them while (equation != string.Empty && equation.First() == '(' && equation.Last() == ')') { equation = RemoveBracketsStartingOnIndex(equation, 0); } // if there is nothing if (equation == string.Empty) { _error = ErrorsEnum.OperatorDoNotHaveEnoughArguments; throw new SyntaxErrorException(); } // get index of operator with highest priority for tree (lowest priority) int opIndex = GetIndexOfOperatorWithLowestPriority(equation); if (opIndex == -1) { // there is no more operators tree.IsOperator = false; tree.Number = StringToDouble(equation, ref _error); } else { // set operator into tree OperatorsEnum op = GetOperatorOnIndex(equation, opIndex); tree.IsOperator = true; tree.Op = op; if (Operators.IsSingleNumberOperator(op)) { // single argument operator -> setup only left side of tree // opIndex should be 0 because double arguments operators are solved before single arg. o. // -> single ar. o. is the last outside brackets (or there is only last number - argument for operator) if (opIndex != 0) { _error = ErrorsEnum.UnknownError; throw new SyntaxErrorException(); } equation = equation.Substring(Operators.GetOperatorFromEnum(op).Length); tree.Left = CreateTree(equation); } else { // double arguments operator -> setup both left and right side of tree string equationLeft = equation.Substring(0, opIndex); string equationRight = equation.Substring(opIndex + Operators.GetOperatorFromEnum(op).Length); tree.Left = CreateTree(equationLeft); tree.Right = CreateTree(equationRight); } } return(tree); }
/// <summary> /// Will check is number is digit (0123456789) and if not -> set error end throw exception /// </summary> /// <param name="c">char to check</param> /// <param name="error">reference to ErrorsEnum which is set before throwing errors</param> // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local public static void CheckIfIsDigit(char c, ref ErrorsEnum error) { if (!char.IsDigit(c)) { error = ErrorsEnum.InvalidNumberFormat; throw new InvalidDataException(); } }
/// <summary> /// will check equation if there are no unknown characters /// </summary> /// <param name="equation">string containing equation</param> /// <returns>true if equation does not contains unknown character else false if contains</returns> private bool CheckUnknownCharacter(string equation) { int i = 0; while (equation.Length > i) { // check if is constant -> the it is good :) if (StringControl.IsFirstCharOfConstantConstant(equation[i]) && StringControl.GetConstantString(equation.Substring(i)) != string.Empty) { i += StringControl.GetConstantString(equation.Substring(i)).Length; } else if (StringControl.IsNumberChar(equation[i])) { // get string of number characters string substring = string.Empty; do { substring += equation[i++]; }while (equation.Length > i && StringControl.IsNumberChar(equation[i])); // check if string can be converted to number try { StringToDouble(substring, ref _error); } catch { return(false); } } else { // get string of all another characters string substring = string.Empty; do { substring += equation[i++]; }while (equation.Length > i && !StringControl.IsNumberChar(equation[i]) && !(StringControl.IsFirstCharOfConstantConstant(equation[i]) && StringControl.GetConstantString(equation.Substring(i)) != string.Empty)); if (!CheckStringOfOperators(substring)) { _error = ErrorsEnum.InvalidSequenceOfCharacters; return(false); } } } return(true); }
/// <summary> /// </summary> /// <param name="equation">string containing equation</param> /// <param name="index">index of ending char of number or ending bracket</param> /// <returns>starting index of number or starting index of corresponding bracket to given bracket</returns> private int GetStartingIndexOfNumberOrStringInsideBracketOnIndex(string equation, int index) { int startingIndex = index; if (equation[index] == ')') { // if there is bracket on index, return index of starting bracket startingIndex = GetStartingBracketOfBracketOnIndex(equation, index); } else { // else check for staring index of number or constant while (startingIndex >= 0 && (StringControl.IsNumberChar(equation[startingIndex]) || StringControl.IsLastCharOfConstantConstant(equation[startingIndex]))) { if (StringControl.IsLastCharOfConstantConstant(equation[startingIndex])) { string constant = StringControl.GetConstantStringByLastChar(equation.Substring(0, startingIndex + 1)); if (constant == string.Empty) { break; } startingIndex -= constant.Length; } else { --startingIndex; } } ++startingIndex; } if (index < startingIndex) { // if there if no number/ constant/ bracket _error = ErrorsEnum.OperatorDoNotHaveEnoughArguments; throw new SyntaxErrorException(); } if (startingIndex == -1) { // shouldn't happened - fixed before solving tree _error = ErrorsEnum.UnknownError; throw new SyntaxErrorException(); } return(startingIndex); }
/// <summary> /// will check whole equation if there is nothing incorrect /// </summary> /// <param name="equation">string containing equation</param> /// <returns>true if equation is correct else false if there is problem</returns> private bool SyntaxCheck(string equation) { if (equation.Length == 0) { _error = ErrorsEnum.EmptyEquation; return(false); } // todo 1. and last item must be number/constant return(CheckUnknownCharacter(equation)); }
/// <summary> /// Converts string tu number /// </summary> /// <param name="str">string containing number</param> /// <param name="error">reference to ErrorsEnum which is set before throwing errors</param> /// <returns>return number representing number in string or set error end throw exception if cant convert</returns> public double StringToDouble(string str, ref ErrorsEnum error) { // check if is constant switch (str) { case Strings.Pi: return(Math.PI); case Strings.Ans: return(_ansValue); case Strings.Memory: return(_memoryValue); } // return Convert.ToDouble(str); // or harder way :) (FloatSeparator can be changed to any char) double number = 0; double floatingPartOfNumber = 0; int index = 0; // convert integer part of number while (str.Length > index && str[index] != StringControl.FloatSeparator) { StringControl.CheckIfIsDigit(str[index], ref error); number *= 10; number += str[index++] - '0'; } // convert floating part of number if (str.Length > index && str[index] == StringControl.FloatSeparator) { index = str.Length - 1; while (str[index] != StringControl.FloatSeparator) { StringControl.CheckIfIsDigit(str[index], ref error); floatingPartOfNumber /= 10; floatingPartOfNumber += str[index--] - '0'; } floatingPartOfNumber /= 10; } return(number + floatingPartOfNumber); }
/// <summary> /// </summary> /// <param name="equation">string containing equation</param> /// <returns>returns number of missing ending brackets or -1 if invalid syntax</returns> private int CheckBrackets(string equation) { // check if there is empty bracket if (equation.Contains("()")) { _error = ErrorsEnum.EmptyBrackets; return(-1); } // creating string consist only of brackets string bracketsString = string.Empty; int i = 0; while (equation.Length > i) { while (equation.Length > i && (equation[i] == '(' || equation[i] == ')')) { bracketsString += equation[i++]; } ++i; } // deleting most internal brackets until there are no right ')' brackets // or there is invalid sequence of brackets while (bracketsString.Contains("()")) { bracketsString = StringControl.RemoveAll(bracketsString, "()"); } // counting missing brackets int missingBrackets = 0; foreach (char bracket in bracketsString) { if (bracket != '(') { // there is invalid sequence of brackets _error = ErrorsEnum.InvalidSequenceOfBrackets; return(-1); } ++missingBrackets; } return(missingBrackets); }
/// <summary> /// </summary> /// <param name="errorsEnum">error</param> /// <returns>returns error in user friendly text</returns> public static string ToString(ErrorsEnum errorsEnum) { switch (errorsEnum) { case ErrorsEnum.None: return("No error occurred"); case ErrorsEnum.UnknownError: return("An unknown error occurred"); case ErrorsEnum.CantDivideByZero: return("Can't divide by zero"); case ErrorsEnum.InvalidSyntax: return("Invalid syntax"); case ErrorsEnum.EmptyEquation: return("Equation can't be empty"); case ErrorsEnum.EmptyBrackets: return("Brackets can't be empty"); case ErrorsEnum.InvalidSequenceOfBrackets: return("Invalid sequence of brackets"); case ErrorsEnum.InvalidNumberFormat: return("Invalid format of number"); case ErrorsEnum.InvalidValueForTrigonometricFunction: return("Invalid value for trigonometric function"); case ErrorsEnum.InvalidSequenceOfCharacters: return("Invalid sequence of characters"); case ErrorsEnum.OperatorDoNotHaveEnoughArguments: return("Operator don't have enough arguments"); default: return("Some error occurred"); } }
/// <summary> /// main calculating function which cares about syntax check and getting result of equation /// </summary> /// <param name="equation">string containing equation</param> /// <returns>result of equation or null if error</returns> public double?Calculate(string equation) { double?result = null; _error = ErrorsEnum.None; // bracket check if (CheckBrackets(equation) != -1) { // preparing equation for processing equation = PrepareEquationForProcessing(equation); // syntax check if (SyntaxCheck(equation)) { try { // creating tree from equation and solving it result = SolveTree(CreateTree(equation)); } catch { // if any error during creating tree occurred return(null); } // setup ans value or handle unknown error which wasn't handled before if (result.HasValue) { _ansValue = result.Value; } else { _error = ErrorsEnum.UnknownError; // shouldn't happened - fixed before solving tree } } } return(result); }
/// <summary> /// </summary> /// <param name="equation">string containing equation</param> /// <param name="index">index of ending char of number or starting bracket</param> /// <returns>ending index of number or ending index of corresponding bracket to given bracket</returns> private int GetEndingIndexOfNumberOrStringInsideBracketOnIndex(string equation, int index) { int endingIndex = index; if (equation[index] == '(') { // if there is bracket on index, return index of starting bracket endingIndex = GetEndingBracketOfBracketOnIndex(equation, index); } else { // else check for staring index of number or constant while (endingIndex < equation.Length && (StringControl.IsNumberChar(equation[endingIndex]) || StringControl.IsConstantChar(equation[endingIndex]))) { ++endingIndex; } --endingIndex; } if (index > endingIndex) { // if there if no number/ constant/ bracket _error = ErrorsEnum.OperatorDoNotHaveEnoughArguments; throw new SyntaxErrorException(); } if (endingIndex == -1) { // shouldn't happened - fixed before solving tree _error = ErrorsEnum.UnknownError; throw new SyntaxErrorException(); } return(endingIndex); }
public ServiceResult(ErrorsEnum code) { Succeeded = false; ErrorResult = Errors.GetError(code); }
public static ServiceResult Error(ErrorsEnum code) { return(new ServiceResult(code)); }
/// <summary> /// will solve equation with one operator /// </summary> /// <param name="o">operator</param> /// <param name="argument1">first argument value</param> /// <param name="argument2">second argument value</param> /// <param name="inRadians">for trigonometric fcs</param> /// <param name="error">will be set, if an error occured</param> /// <returns>Result of equation if success or null if fail</returns> public static double SolveOperator(OperatorsEnum o, double?argument1, double?argument2, bool inRadians, ref ErrorsEnum error) { // check if required arguments has value if (!IsSingleNumberOperator(o) && !argument2.HasValue || !argument1.HasValue) { throw new SyntaxErrorException(); // shouldn't happened - fixed before solving tree } // solve based on operator switch (o) { // disable ReSharper warning, which is solved by first condition // ReSharper disable PossibleInvalidOperationException case OperatorsEnum.Plus: return(argument1.Value + argument2.Value); case OperatorsEnum.Minus: return(-argument1.Value); case OperatorsEnum.Multiply: return(argument1.Value * argument2.Value); case OperatorsEnum.Pow: return(Calculations.Pow(argument1.Value, argument2.Value)); case OperatorsEnum.Sqrt: return(Calculations.Sqrt(argument1.Value, argument2.Value)); case OperatorsEnum.Factorial: return(Calculations.Factorial(argument1.Value)); case OperatorsEnum.Modulo: return(argument1.Value % argument2.Value); case OperatorsEnum.Sinus: return(Calculations.Sin(argument1.Value, inRadians)); case OperatorsEnum.Cosinus: return(Calculations.Cos(argument1.Value, inRadians)); case OperatorsEnum.Tangents: return(Calculations.Tan(argument1.Value, inRadians)); case OperatorsEnum.Cotangents: return(Calculations.Ctg(argument1.Value, inRadians)); case OperatorsEnum.Asinus: return(Calculations.Asin(argument1.Value, inRadians)); case OperatorsEnum.Acosinus: return(Calculations.Acos(argument1.Value, inRadians)); case OperatorsEnum.Atangents: return(Calculations.Atan(argument1.Value, inRadians)); case OperatorsEnum.Acotangents: return(Calculations.Actg(argument1.Value, inRadians)); case OperatorsEnum.Divide: // can't divide by 0 if (argument2.Value.Equals(0)) { error = ErrorsEnum.CantDivideByZero; throw new InvalidDataException(); } return(argument1.Value / argument2.Value); } // if operator is not in the list throw new SyntaxErrorException(); // shouldn't happened - fixed before solving tree }
public static ScriptResponse setupErrorResponse(ErrorsEnum otee, string token) { return setupErrorResponse(EnumHandler.getErrorNumberAttribute(otee), EnumHandler.getErrorDescriptionAttribute(otee), token); }
public static ScriptResponse setupErrorResponse(ErrorsEnum otee) { return setupErrorResponse(otee, ""); }
public static ScriptResponse setupErrorResponse(ErrorsEnum otee, string token) { return(setupErrorResponse(EnumHandler.getErrorNumberAttribute(otee), EnumHandler.getErrorDescriptionAttribute(otee), token)); }
public static ScriptResponse setupErrorResponse(ErrorsEnum otee) { return(setupErrorResponse(otee, "")); }
public static ErrorDto GetError(ErrorsEnum code) { return(new ErrorDto { ErrorCode = (int)code, ErrorContent = Values[code] }); }
public static ErrorDto GetError(ErrorsEnum code, string content) { return(new ErrorDto { ErrorCode = (int)code, ErrorContent = content }); }