// returns the added operand node public static MathNode ParseOperand(string input) { if (input == null) { throw new UberScriptException("AddOperand input was null!"); } if (input == "") { throw new UberScriptException("AddOperand input was an empty string!"); } Object operand = input; OpType opType = OpType.Unassigned; try { int numCommas = 0; for (int i = 0; i < input.Length; i++) { if (input[i] == ',') numCommas++; } if (input.StartsWith("0x")) { try { if (isNegative) // might fail here { operand = Convert.ToInt32(input.Substring(2), 16); opType = OpType.Int; } else { operand = Convert.ToUInt64(input.Substring(2), 16); // try to use int if at all possible if ((UInt64)operand < 2147483647) // 2^31 - 1 { operand = Convert.ToInt32(input.Substring(2), 16); opType = OpType.Int; } else opType = OpType.UInt64; } } catch // (InvalidCastException e) { // must be a string operand = input; opType = OpType.String; } } else if (char.IsNumber(input[0]) || input[0] == '.') { double doubleVal; bool result = double.TryParse(input, out doubleVal); if (result == false) { operand = input; // must be something like 016hello, so just treat it as a string opType = OpType.String; } else { if (isNegative) { doubleVal = -doubleVal; isNegative = false; } if (!input.Contains('.') && doubleVal % 1 < 0.0009765625) // 2^-10 { // close enough to an integer value operand = (int)doubleVal; opType = OpType.Int; } else { operand = doubleVal; opType = OpType.Double; } } } else if (input == "null") { opType = OpType.Null; operand = null; } else if (input.StartsWith("\"")) { // inside a quotation--> parse out the innards and set it to a string if (!input.EndsWith("\"") || input.Length == 1) { throw new UberScriptException("ParseOperand input started with \" but did not end with \"... it must be balanced!"); } input = input.Substring(1, input.Length - 2); // remove the front and back "" bool justEscapedBackslash = false; for (int ix = 0; ix < input.Length; ix++) { if (ix > 0 && input[ix - 1] == '\\') { // not super efficient, but oh well, it's only run once if (!justEscapedBackslash) { if (input[ix] == '"') { input = input.Substring(0, ix - 1) + input.Substring(ix); // remove the \, keep the " ix--; } else if (input[ix] == 't') { input = input.Substring(0, ix - 1) + "\t" + input.Substring(ix + 1); // remove the \ and add a tab ix--; } else if (input[ix] == 'n') { input = input.Substring(0, ix - 1) + "\n" + input.Substring(ix + 1); // remove the \ and add a new line ix--; } else if (input[ix] == 'r') { input = input.Substring(0, ix - 1) + "\r" + input.Substring(ix + 1); // remove the \ and add a carriage return ix--; } else if (input[ix] == '\\') { input = input.Substring(0, ix - 1) + input.Substring(ix); // keep only one of the \ characters justEscapedBackslash = true; continue; } } // otherwise ignore it } justEscapedBackslash = false; } operand = input; opType = OpType.String; } else if (UberScriptFunctions.IsFunctionString(input)) { MathNode latestRootNode = currentRoot; // currentRoot is replaced when FunctionNode adds a mathtree for each arg currentRoot = null; operand = new FunctionNode(null, input); // can't add LineNumber here :( if (isNegative) { ((FunctionNode)operand).NegateOutput = true; isNegative = false; } opType = OpType.Func; currentRoot = latestRootNode; } // NOTE: While the performance is not as good (perhaps), I'm going to rely on parsing list accession (e.g. objs.mobs[objs.mobs.count - 1]) // on the fly (as is done in the PropertySetters and PropertyGetters functions) rather than pre-parsing it. /* else if (UberScriptFunctions.IsArrayAccessor(input)) { MathNode latestRootNode = currentRoot; // currentRoot is replaced when FunctionNode adds a mathtree for each arg currentRoot = null; operand = new ListAccessNode(null, input); // can't add LineNumber here :( if (isNegative) { ((ListAccessNode)operand).NegateOutput = true; isNegative = false; } opType = OpType.ListAccess; currentRoot = latestRootNode; }*/ /* // I'm not going to handle literal points e.g. (1,2,3)... use the LOC function instead (so you can do math in it) else if (numCommas > 1) // it must be a location if it is not a function and has 2 commas in it { operand = "(" + input + ")"; opType = OpType.String; }*/ else { operand = input; opType = OpType.String; } MathNode newOperandNode = new MathNode(null, null, opType, TreePriority.Operand, operand); // assigned into tree in constructor! return newOperandNode; } catch (Exception e) { Console.WriteLine("AddOperand error: " + e.Message + "\n" + e.StackTrace); throw new UberScriptException("AddOperand error for " + input, e); } }
public static void AddOperationNode(ref string input, OpType opType, TreePriority priority, int i, ref int currentIndex) { string operand = input.Substring(currentIndex, i - currentIndex); MathNode newNode = new MathNode(null, null, opType, priority); char prevChar = i > 0 ? input[i-1] : '\0'; bool twoCharOperator = false; char nextChar; if (opType == OpType.And || opType == OpType.Or || opType == OpType.NotEqualTo || opType == OpType.EqualTo || opType == OpType.GThanOrEqualTo || opType == OpType.LThanOrEqualTo) { nextChar = input.Length > (i+2) ? input[i+2] : '\0'; twoCharOperator = true; } else { nextChar = input.Length > (i+1) ? input[i+1] : '\0'; } if (operand == "") { // the only character possible before an operator is ) if (i > 0 && input[i - 1] == ')') { bool hasFollowingOpenParen = false; // special case--requires decreased priority when inserting this node if (nextChar == '(') { hasFollowingOpenParen = true; } if (hasFollowingOpenParen) { TreePriority prevPriority = newNode.Priority; newNode.Priority = TreePriority.AddSub; // SHOULD THIS BE CHANGED TO JUST DECREASING BY ONE? OR ALWAYS ADD SUB? InsertIntoTree(currentRoot, newNode); newNode.Priority = prevPriority; } else InsertIntoTree(currentRoot, newNode); } else throw new UberScriptException("Math parse error: no operand before + for input= " + input); } else { if (currentRoot == null) { currentRoot = newNode; InsertIntoTree(currentRoot, ParseOperand(operand)); } else { InsertIntoTree(currentRoot, ParseOperand(operand)); InsertIntoTree(currentRoot, newNode); } } if (twoCharOperator) currentIndex = i + 2; else currentIndex = i + 1; }
public static void InsertIntoTree(MathNode nodeToCheck, MathNode newNode) { if (nodeToCheck == null) { currentRoot = newNode; return; } try { if (newNode.Priority == TreePriority.Unassigned) { throw new Exception("Attempted to insert MathNode with unassigned priority--Not allowed!"); } if (newNode.Priority == TreePriority.Operand) { if (nodeToCheck.OpTypeVal == OpType.OpenParenthesis && newNode.OpTypeVal != OpType.OpenParenthesis) { // should never be more than 1 open parenthesis in a row (b/c currentRootNode is replaced)... // remove the Open Parenthesis node--it was just a placerholder ReplaceNode(nodeToCheck, newNode, true); // becomes the new Current root until the next closing parenthesis return; } // should never happen that two operands land on each other in this function // EXCEPT if you get 2 open parentheses in a row if (nodeToCheck.Priority > TreePriority.Operand || (nodeToCheck.OpTypeVal == OpType.OpenParenthesis && newNode.OpTypeVal == OpType.OpenParenthesis)) { if (nodeToCheck.Left == null) { nodeToCheck.Left = newNode; } else if (nodeToCheck.Left.OpTypeVal == OpType.OpenParenthesis) { InsertIntoTree(nodeToCheck.Left, newNode); } // the only time operand can go left else if (nodeToCheck.Right == null) { nodeToCheck.Right = newNode; } else InsertIntoTree(nodeToCheck.Right, newNode); } else { throw new Exception("Cannot have operand land on operand in InsertIntoTree method!"); } } else // priority is > Operand... this will either push a branch down or replace an operator somewhere { if (nodeToCheck.OpTypeVal == OpType.OpenParenthesis) { // something like ((5+5)*3), the * would have hit this case // remove the Open Parenthesis node--it was just a placerholder ReplaceNode(nodeToCheck, newNode, true); // becomes the new Current root until the next closing parenthesis } else if (nodeToCheck.Priority >= newNode.Priority) // push the branch down { if (nodeToCheck.Parent != null) { if (((MathNode)nodeToCheck.Parent).Right == nodeToCheck) { ((MathNode)nodeToCheck.Parent).Right = newNode; } else { ((MathNode)nodeToCheck.Parent).Left = newNode; } } else { currentRoot = newNode; } if (currentRoot == nodeToCheck) currentRoot = newNode; newNode.Left = nodeToCheck; } else // (nodeToCheck.Priority < newNode.Priority) // get underneath it, push operand down { if (nodeToCheck.Left == null) { // DON"T throw new Exception("InsertIntoTree Higher priority operator found null left node!"); } // actually this can happen in a case like (4+10), where the ( is replaced with the // 4 and then the + tries to follow suit, but 4 is now the root node. if (nodeToCheck.Priority == TreePriority.Operand) { if (nodeToCheck.Parent != null) { if (((MathNode)nodeToCheck.Parent).Right == nodeToCheck) { ((MathNode)nodeToCheck.Parent).Right = newNode; } else { ((MathNode)nodeToCheck.Parent).Left = newNode; } if (currentRoot == nodeToCheck) currentRoot = newNode; } else { currentRoot = newNode; } newNode.Left = nodeToCheck; } } else if (nodeToCheck.Right == null) { throw new Exception("Right node should not be null here!"); } else if (nodeToCheck.Right.Priority == TreePriority.Operand) { MathNode oldRight = ReplaceNode(nodeToCheck.Right, newNode, false); newNode.Left = oldRight; } else InsertIntoTree(nodeToCheck.Right, newNode); } } } catch (Exception e) { throw new UberScriptException("InsertIntoTree error: ", e); } }
public void ParseMath(string input) { int currentIndex = 0; Stack<MathNode> prevRootNodes = new Stack<MathNode>(); currentRoot = null; isNegative = false; int numOpenParensInFunctionCallString = 0; // should be 0 if we are not in a function call, never less than 0 int totalOpenParens = 0; // should never be less than 0 string operatorsSupportingUnaryMinus = "+-*/^%(<=>"; bool insideQuotation = false; int totalOpenSquareBracket = 0; if (input == "") { currentRoot = new MathNode(null, null, OpType.String, TreePriority.Operand, String.Empty); Children.Add(currentRoot); return; } // if it is an array, there can be nothing more in the math tree if (input.StartsWith("[") && input.EndsWith("]")) { MathNode arrayNode = new MathNode(null, input, OpType.Array, TreePriority.Infinite); string inArray = input.Substring(1, input.Length - 2); List<string> elements = new List<string>(); for (int i = 0; i < inArray.Length; i++) { char c = inArray[i]; if (insideQuotation && c != '"') { continue; } if (c == '(') { totalOpenParens += 1; } else if (c == ')') { totalOpenParens -= 1; if (totalOpenParens < 0) { throw new Exception("Unbalanced () characters in math string!"); } } else if (c == '[') { totalOpenSquareBracket += 1; } else if (c == ']') { totalOpenSquareBracket -= 1; if (totalOpenSquareBracket < 0) { throw new Exception("Unbalanced [] characters in math string!"); } } else { if (totalOpenParens > 0 || totalOpenSquareBracket > 0) continue; if (c == '"') { /* I'm not sure why I thought I need to do this here; it's taken care of in the MathTree parsing if (i > 0 && inArray[i-1] == '\\') { // not super efficient, but oh well, it's only run once inArray = inArray.Substring(0, i - 1) + inArray.Substring(i); // remove the \, keep the " i--; } else { inArray = inArray.Substring(0, i) + inArray.Substring(i+1); // remove the " i--; */ insideQuotation = !insideQuotation; //} } else if (c == ',') { elements.Add(inArray.Substring(0, i)); inArray = inArray.Substring(i+1); i = -1; } } } if (inArray.Length > 0) { elements.Add(inArray); } // add final element ArrayList arrayList = new ArrayList(elements.Count + 10); foreach (string element in elements) { arrayList.Add(new MathTree(null, element)); } arrayNode.Value = arrayList; Children.Add(arrayNode); return; } bool justEscapedBackslash = false; for (int i = 0; i < input.Length; i++) { char c = input[i]; string arg; if (insideQuotation && c != '"') { if (c == '\\') { if (i > 0 && input[i - 1] == '\\' && !justEscapedBackslash) { justEscapedBackslash = true; continue; } } justEscapedBackslash = false; continue; } if (c == '"') { if (i > 0 && input[i - 1] == '\\' && !justEscapedBackslash) { continue; // it's an escaped \" character } else { // --> I'm putting this in the ParseOperand area //input = input.Substring(0, i) + input.Substring(i+1); // remove the " //i--; insideQuotation = !insideQuotation; } } if (totalOpenSquareBracket > 0 && c != ']') { if (c == '[') { totalOpenSquareBracket++; } continue; } else if (c == '[') { totalOpenSquareBracket++; } else if (c == ']') { if (totalOpenSquareBracket > 0) { totalOpenSquareBracket--; } else { throw new Exception("Unbalanced [] characters in list accessing string!"); } } if (numOpenParensInFunctionCallString > 0 && c != '(' && c != ')') { // don't do anything in the middle of a function string continue; } if (c == '|') { if (input[i + 1] == '|') { AddOperationNode(ref input, OpType.Or, TreePriority.Or, i, ref currentIndex); i++; } else { throw new UberScriptException("Single | encountered! Use || for logical 'or' operator. Note that the bitwise '|' operator currently not supported!"); //AddOperationNode(ref input, OpType.BitOr, TreePriority.BitAnd, i, ref currentIndex); } } else if (c == '&') { if (input[i + 1] == '&') { AddOperationNode(ref input, OpType.And, TreePriority.And, i, ref currentIndex); i++; } else { throw new UberScriptException("Single & encountered! Use && for logical 'and' operator. Note that the bitwise '&' operator currently not supported!"); //AddOperationNode(ref input, OpType.BitAnd, TreePriority.BitAnd, i, ref currentIndex); } } else if (c == '>') { if (input[i+1] == '=') { AddOperationNode(ref input, OpType.GThanOrEqualTo, TreePriority.Comparison, i, ref currentIndex); i++; } else { AddOperationNode(ref input, OpType.GThan, TreePriority.Comparison, i, ref currentIndex); } } else if (c == '<') { if (input[i+1] == '=') { AddOperationNode(ref input, OpType.LThanOrEqualTo, TreePriority.Comparison, i, ref currentIndex); i++; } else { AddOperationNode(ref input, OpType.LThan, TreePriority.Comparison, i, ref currentIndex); } } else if (c == '!') { if (input[i + 1] == '=') { AddOperationNode(ref input, OpType.NotEqualTo, TreePriority.Comparison, i, ref currentIndex); i++; } else { throw new UberScriptException("Cannot have a single = sign!"); } } else if (c == '=') { if (input[i+1] == '=') { AddOperationNode(ref input, OpType.EqualTo, TreePriority.Comparison, i, ref currentIndex); i++; } else { throw new UberScriptException("Cannot have a single = sign!"); } } else if (c == '+') { AddOperationNode(ref input, OpType.Add, TreePriority.AddSub, i, ref currentIndex); } else if (c == '-') { // i == 0 means a statment is STARTING with -, e.g. -6 // otherwise there is something like this ...+-6 or ...*-6, etc if (i == 0 || (i > 0 && (operatorsSupportingUnaryMinus.Contains(input[i - 1])))) { isNegative = !isNegative; currentIndex = i + 1; } else { AddOperationNode(ref input, OpType.Sub, TreePriority.AddSub, i, ref currentIndex); } } else if (c == '*') { AddOperationNode(ref input, OpType.Mul, TreePriority.MultDiv, i, ref currentIndex); } else if (c == '/') { AddOperationNode(ref input, OpType.Div, TreePriority.MultDiv, i, ref currentIndex); } else if (c == '^') { AddOperationNode(ref input, OpType.Pow, TreePriority.Power, i, ref currentIndex); } else if (c == '%') { AddOperationNode(ref input, OpType.Mod, TreePriority.MultDiv, i, ref currentIndex); } else if (c == '(') { totalOpenParens++; // must check if it is a function call if (numOpenParensInFunctionCallString == 0) { if (UberScriptFunctions.IsFunctionString(input.Substring(currentIndex, i - currentIndex).Trim())) { numOpenParensInFunctionCallString++; continue; } // it's not a function call, it's an order of operations open parenthesis prevRootNodes.Push(currentRoot); MathNode openParenPlaceholder = new MathNode(null, null, OpType.OpenParenthesis, TreePriority.Operand); InsertIntoTree(currentRoot, openParenPlaceholder); currentRoot = openParenPlaceholder; currentIndex = i + 1; } else { numOpenParensInFunctionCallString++; // keep incrementing it } } else if (c == ')') { totalOpenParens--; if (totalOpenParens < 0) { throw new Exception("Unbalanced () characters in math string!"); } if (numOpenParensInFunctionCallString > 0) { numOpenParensInFunctionCallString--; if (numOpenParensInFunctionCallString < 0) { throw new Exception("Unbalanced () characters in function call string!"); } } else { // should be an operand or ) right before this ) arg = input.Substring(currentIndex, i - currentIndex).Trim(); if (arg == "" && !(i > 0 && input[i - 1] == ')')) { throw new UberScriptException("Math parse error: no operand before operator for input=" + input); } if (currentRoot == null) { throw new UberScriptException("Math parse error: can't have ) without a ( currentRoot! input=" + input); } // should be impossible if (arg != "") InsertIntoTree(currentRoot, ParseOperand(arg)); currentIndex = i + 1; MathNode prevRootNode = prevRootNodes.Pop(); currentRoot.Priority = TreePriority.Infinite; if (prevRootNode != null) { currentRoot = prevRootNode; // return up a level } // else the first character in the input was (, so there was no root node initially, so keep the currentNode } } } if (insideQuotation) { throw new UberScriptException("Unbalanced \" characters! You must terminate strings with \""); }; if (totalOpenParens > 0) { throw new UberScriptException("Did not have matching ()!"); } if (totalOpenSquareBracket > 0) { throw new UberScriptException("Did not have matching []!"); } if (currentIndex < input.Length) { if (currentRoot == null) { currentRoot = ParseOperand(input.Substring(currentIndex, input.Length - currentIndex)); } else { InsertIntoTree(currentRoot, ParseOperand(input.Substring(currentIndex, input.Length - currentIndex))); } } Children.Add(currentRoot); }
/// <summary> /// Replaces the node in the tree, returns the replaced node /// </summary> /// <param name="nodeToReplace"></param> /// <param name="newNode"></param> /// <param name="replaceCurrent"></param> /// <returns></returns> public static MathNode ReplaceNode(MathNode nodeToReplace, MathNode newNode, bool replaceCurrent) { if (nodeToReplace.Parent == null) { currentRoot = newNode; // we're at the top root newNode.Left = nodeToReplace.Left; newNode.Right = nodeToReplace.Right; return nodeToReplace; } // in case it was the only thing in the tree if (((MathNode)nodeToReplace.Parent).Right == nodeToReplace) { ((MathNode)nodeToReplace.Parent).Right = newNode; } else { ((MathNode)nodeToReplace.Parent).Left = newNode; } newNode.Left = nodeToReplace.Left; newNode.Right = nodeToReplace.Right; if (replaceCurrent) { currentRoot = newNode; } return nodeToReplace; }
/// <summary> /// Ugly function for taking Objects from the MathTree and adding them together... /// Not sure if there might be a better way (without calling up the C# compiler /// to sort things out which I think would be terrible performance) /// </summary> /// <param name="node"></param> /// <returns></returns> public static Object Calculate(TriggerObject trigObj, MathNode node) { // ordered in the most probable order, (in my opinion) bool isInDictionary = false; if (node == null) { return null; } if (node.Left == null && node.Right == null) { if (node.OpTypeVal == OpType.Func) { return ((FunctionNode)node.Value).Execute(trigObj, false); // true??? } else if (node.Value is ArrayList) { ArrayList original = (ArrayList)node.Value; if (original.Count > 0 && original[0] is MathTree) { // if 1 element is a mathtree, then they are all mathtrees // ... created using this syntax: ["hello", "heh" + " hah"] ArrayList outputList = new ArrayList(original.Count); for (int i = 0; i < original.Count; i++) { outputList.Add(((MathTree)original[i]).Calculate(trigObj)); } return outputList; } // otherwise it's a regular arraylist--just return it return original; } else if (node.Value is string && (string)node.Value != string.Empty) { string nodeValueString = (string)node.Value; string nodeValueStringLower = nodeValueString.ToLower(); if (nodeValueStringLower == "false") { return false; } else if (nodeValueStringLower == "true") { return true; } // check if it is one of the local or global function ints, strings, doubles, or objs else { object possibleReturnValue = CheckDictionaries(trigObj, nodeValueString, out isInDictionary); if (isInDictionary) { return possibleReturnValue; } } } return node.Value; } Object operand1; Object operand2; if (node.Left.OpTypeVal == OpType.Int || node.Left.OpTypeVal == OpType.Double || node.Left.OpTypeVal == OpType.String || node.Left.OpTypeVal == OpType.UInt64 || node.Left.OpTypeVal == OpType.Bool) { operand1 = node.Left.Value; if (operand1 is string && (string)operand1 != "") { // check if it is one of the local or global function ints, strings, doubles, or objs string operand1String = (string)operand1; string operand1StringLower = operand1String.ToLower(); if (operand1StringLower == "false") { operand1 = false; } else if (operand1StringLower == "true") { operand1 = true; } object possibleReturnValue = CheckDictionaries(trigObj, operand1String, out isInDictionary); if (isInDictionary) { operand1 = possibleReturnValue; } } } else { operand1 = Calculate(trigObj, node.Left); } // hacky solution to extraneous parenthesis if (node.OpTypeVal == OpType.OpenParenthesis) { return operand1; } if (node.OpTypeVal == OpType.And) { // check whether we even need to find operand 2 (since if the // first argument is false, then arg1 && arg2 is false if (operand1 is bool) { if ((bool)operand1 == false) { return false; } } else { throw new UberScriptException("Cannot use && operator between non boolean: " + operand1); } } else if (node.OpTypeVal == OpType.Or) { // check whether we even need to find operand 2 (since if the // first argument is true, then arg1 || arg2 is true if (operand1 is bool) { if ((bool)operand1) { return true; } } else { throw new UberScriptException("Cannot use || operator between non boolean: " + operand1); } } if (node.Right.OpTypeVal == OpType.Int || node.Right.OpTypeVal == OpType.Double || node.Right.OpTypeVal == OpType.String || node.Right.OpTypeVal == OpType.UInt64 || node.Left.OpTypeVal == OpType.Bool) { operand2 = node.Right.Value; if (operand2 is string && (string)operand2 != "") { // check if it is one of the local or global function ints, strings, doubles, or objs string operand2String = (string)operand2; string operand2StringLower = operand2String.ToLower(); if (operand2StringLower == "false") { operand2 = false; } else if (operand2StringLower == "true") { operand2 = true; } object possibleReturnValue = CheckDictionaries(trigObj, operand2String, out isInDictionary); if (isInDictionary) { operand2 = possibleReturnValue; } } } else { operand2 = Calculate(trigObj, node.Right); } switch (node.OpTypeVal) { case OpType.Add: if (operand1 is int) { if (operand2 is int) { return (int)operand1 + (int)operand2; } else if (operand2 is double) { return (int)operand1 + (double)operand2; } else if (operand2 is string) { return operand1 + (string)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) + (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 + (int)operand2; } else if (operand2 is double) { return (double)operand1 + (double)operand2; } else if (operand2 is string) { return operand1 + (string)operand2; } else if (operand2 is UInt64) { return (double)operand1 + (UInt64)operand2; } } else if (operand1 is string) { return (string)operand1 + operand2; } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 + (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 + (double)operand2; } else if (operand2 is string) { return operand1 + (string)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 + (UInt64)operand2; } } else if (operand2 is string) { return operand1 + (string)operand2; } else if (operand1 is DateTime) { if (operand2 is TimeSpan) { return (DateTime)operand1 + (TimeSpan)operand2; } } break; case OpType.Func: // evaluate the function, if it isn't one of the 4 "primitives", then call return ToString on it. Object output = ((FunctionNode)node.Value).Execute(trigObj, true); if (output is int || output is double || output is string || output is UInt64) { return output; } //if (output is Mobile) return ((Mobile)output).Serial; //if (output is Item) return ((Item)output).Serial; return output.ToString(); case OpType.Sub: if (operand1 is string) { throw new UberScriptException("attempted to subtract using a string!:" + operand1); } if (operand2 is string) { throw new UberScriptException("attempted to subtract using a string!:" + operand2); } if (operand1 is int) { if (operand2 is int) { return (int)operand1 - (int)operand2; } else if (operand2 is double) { return (int)operand1 - (double)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) - (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 - (int)operand2; } else if (operand2 is double) { return (double)operand1 - (double)operand2; } else if (operand2 is UInt64) { return (double)operand1 - (UInt64)operand2; } } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 - (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 - (double)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 - (UInt64)operand2; } } else if (operand1 is DateTime) { if (operand2 is DateTime) { return (DateTime)operand1 - (DateTime)operand2; } else if (operand2 is TimeSpan) { return (DateTime)operand1 - (TimeSpan)operand2; } } break; case OpType.Mul: if (operand1 is string) { throw new UberScriptException("attempted to multiply using a string!:" + operand1); } if (operand2 is string) { throw new UberScriptException("attempted to multiply using a string!:" + operand2); } if (operand1 is int) { if (operand2 is int) { return (int)operand1 * (int)operand2; } else if (operand2 is double) { return (int)operand1 * (double)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) * (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 * (int)operand2; } else if (operand2 is double) { return (double)operand1 * (double)operand2; } else if (operand2 is UInt64) { return (double)operand1 * (UInt64)operand2; } } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 * (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 * (double)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 * (UInt64)operand2; } } break; case OpType.GThan: if (operand1 == null || operand2 == null) { throw new UberScriptException("GThan had null argument!"); } if (operand1 is string) { throw new UberScriptException("attempted to GThan using a string!:" + operand1); } if (operand2 is string) { throw new UberScriptException("attempted to GThan using a string!:" + operand2); } if (operand1 is int) { if (operand2 is int) { return (int)operand1 > (int)operand2; } else if (operand2 is double) { return (int)operand1 > (double)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) > (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 > (int)operand2; } else if (operand2 is double) { return (double)operand1 > (double)operand2; } else if (operand2 is UInt64) { return (double)operand1 > (UInt64)operand2; } } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 > (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 > (double)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 > (UInt64)operand2; } } else if (operand1 is DateTime) { if (operand2 is DateTime) { return (DateTime)operand1 > (DateTime)operand2; } } break; case OpType.LThan: if (operand1 == null || operand2 == null) { throw new UberScriptException("LThan had null argument!"); } if (operand1 is string) { throw new UberScriptException("attempted to LThan using a string!:" + operand1); } if (operand2 is string) { throw new UberScriptException("attempted to LThan using a string!:" + operand2); } if (operand1 is int) { if (operand2 is int) { return (int)operand1 < (int)operand2; } else if (operand2 is double) { return (int)operand1 < (double)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) < (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 < (int)operand2; } else if (operand2 is double) { return (double)operand1 < (double)operand2; } else if (operand2 is UInt64) { return (double)operand1 < (UInt64)operand2; } } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 < (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 < (double)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 < (UInt64)operand2; } } else if (operand1 is DateTime) { if (operand2 is DateTime) { return (DateTime)operand1 < (DateTime)operand2; } } break; case OpType.GThanOrEqualTo: if (operand1 == null || operand2 == null) { throw new UberScriptException("GThanOrEqualTo had null argument!"); } if (operand1 is string) { throw new UberScriptException("attempted to GThanOrEqualTo using a string!:" + operand1); } if (operand2 is string) { throw new UberScriptException("attempted to GThanOrEqualTo using a string!:" + operand2); } if (operand1 is int) { if (operand2 is int) { return (int)operand1 >= (int)operand2; } else if (operand2 is double) { return (int)operand1 >= (double)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) >= (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 >= (int)operand2; } else if (operand2 is double) { return (double)operand1 >= (double)operand2; } else if (operand2 is UInt64) { return (double)operand1 >= (UInt64)operand2; } } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 >= (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 >= (double)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 >= (UInt64)operand2; } } else if (operand1 is DateTime) { if (operand2 is DateTime) { return (DateTime)operand1 >= (DateTime)operand2; } } break; case OpType.LThanOrEqualTo: if (operand1 == null || operand2 == null) { throw new UberScriptException("LThanOrEqualTo had null argument!"); } if (operand1 is string) { throw new UberScriptException("attempted to LThanOrEqualTo using a string!:" + operand1); } if (operand2 is string) { throw new UberScriptException("attempted to LThanOrEqualTo using a string!:" + operand2); } if (operand1 is int) { if (operand2 is int) { return (int)operand1 <= (int)operand2; } else if (operand2 is double) { return (int)operand1 <= (double)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) <= (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 <= (int)operand2; } else if (operand2 is double) { return (double)operand1 <= (double)operand2; } else if (operand2 is UInt64) { return (double)operand1 <= (UInt64)operand2; } } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 <= (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 <= (double)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 <= (UInt64)operand2; } } else if (operand1 is DateTime) { if (operand2 is DateTime) { return (DateTime)operand1 <= (DateTime)operand2; } } break; case OpType.EqualTo: if (operand1 == operand2) { return true; } if (operand1 != null && operand2 == null) { return false; } if (operand1 == null && operand2 != null) { return false; } if (operand1 is string && !(operand2 is string)) { return ((string)operand1).ToLower() == (operand2 == null ? "null" : operand2.ToString().ToLower()); } if (!(operand1 is string) && operand2 is string) { return (operand1 == null ? "null" : operand1.ToString().ToLower()) == ((string)operand2).ToLower(); } if (operand1 is string && operand2 is string) { return ((string)operand1).ToLower() == ((string)operand2).ToLower(); } if (operand1 is int) { if (operand2 is int) { return (int)operand1 == (int)operand2; } else if (operand2 is double) { return (int)operand1 == (double)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) == (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 == (int)operand2; } else if (operand2 is double) { return (double)operand1 == (double)operand2; } else if (operand2 is UInt64) { return (double)operand1 == (UInt64)operand2; } } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 == (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 == (double)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 == (UInt64)operand2; } } else if (operand1 is DateTime) { if (operand2 is DateTime) { return (DateTime)operand1 == (DateTime)operand2; } } else { return operand1.Equals(operand2); // could be objects } break; case OpType.NotEqualTo: if (operand1 == operand2) { return false; } if (operand1 != null && operand2 == null) { return true; } if (operand1 == null && operand2 != null) { return true; } if (operand1 is string && !(operand2 is string)) { return ((string)operand1).ToLower() == (operand2 == null ? "null" : operand2.ToString().ToLower()); } if (!(operand1 is string) && operand2 is string) { return (operand1 == null ? "null" : operand1.ToString().ToLower()) == ((string)operand2).ToLower(); } if (operand1 is string && operand2 is string) { return ((string)operand1).ToLower() != ((string)operand2).ToLower(); } if (operand1 is int) { if (operand2 is int) { return (int)operand1 != (int)operand2; } else if (operand2 is double) { return (int)operand1 != (double)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) != (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 != (int)operand2; } else if (operand2 is double) { return (double)operand1 != (double)operand2; } else if (operand2 is UInt64) { return (double)operand1 != (UInt64)operand2; } } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 != (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 != (double)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 != (UInt64)operand2; } } else if (operand1 is DateTime) { if (operand2 is DateTime) { return (DateTime)operand1 != (DateTime)operand2; } } else { return !operand1.Equals(operand2); // could be objects } break; case OpType.And: // if we have reached this point, then we already know that operand1 is true! // (because right after finding the first operand we check whether it's false or not) if (!(operand2 is bool)) { throw new UberScriptException("Cannot use && operator between non booleans: " + operand1 + " " + operand2); } return operand2; case OpType.Or: // if we have reached this point, then we already know that operand1 is false! // (because right after finding the first operand we check whether it's true or not) if (!(operand2 is bool)) { throw new UberScriptException("Cannot use || operator between non booleans: " + operand1 + " " + operand2); } return (bool)operand2; case OpType.Div: if (operand1 is string) { throw new UberScriptException("attempted to multiply using a string!:" + operand1); } if (operand2 is string) { throw new UberScriptException("attempted to multiply using a string!:" + operand2); } if (operand1 is int) { if (operand2 is int) { return (int)operand1 / (int)operand2; } else if (operand2 is double) { return (int)operand1 / (double)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) / (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 / (int)operand2; } else if (operand2 is double) { return (double)operand1 / (double)operand2; } else if (operand2 is UInt64) { return (double)operand1 / (UInt64)operand2; } } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 / (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 / (double)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 / (UInt64)operand2; } } break; case OpType.Pow: if (operand1 is string) { throw new UberScriptException("attempted to multiply using a string!:" + operand1); } if (operand2 is string) { throw new UberScriptException("attempted to multiply using a string!:" + operand2); } if (operand1 is int) { if (operand2 is int) { return Math.Pow((int)operand1, (int)operand2); } else if (operand2 is double) { return Math.Pow((int)operand1, (double)operand2); } else if (operand2 is UInt64) { return Math.Pow(Convert.ToUInt64(operand1), (UInt64)operand2); } } else if (operand1 is double) { if (operand2 is int) { return Math.Pow((double)operand1, (int)operand2); } else if (operand2 is double) { return Math.Pow((double)operand1, (double)operand2); } else if (operand2 is UInt64) { return Math.Pow((double)operand1, (UInt64)operand2); } } else if (operand1 is UInt64) { if (operand2 is int) { return Math.Pow((UInt64)operand1, (UInt64)operand2); } else if (operand2 is double) { return Math.Pow((UInt64)operand1, (double)operand2); } else if (operand2 is UInt64) { return Math.Pow((UInt64)operand1, (UInt64)operand2); } } break; case OpType.Mod: if (operand1 is string) { throw new UberScriptException("attempted to multiply using a string!:" + operand1); } if (operand2 is string) { throw new UberScriptException("attempted to multiply using a string!:" + operand2); } if (operand1 is int) { if (operand2 is int) { return (int)operand1 % (int)operand2; } else if (operand2 is double) { return (int)operand1 % (double)operand2; } else if (operand2 is UInt64) { return Convert.ToUInt64(operand1) % (UInt64)operand2; } } else if (operand1 is double) { if (operand2 is int) { return (double)operand1 % (int)operand2; } else if (operand2 is double) { return (double)operand1 % (double)operand2; } else if (operand2 is UInt64) { return (double)operand1 % (UInt64)operand2; } } else if (operand1 is UInt64) { if (operand2 is int) { return (UInt64)operand1 % (UInt64)operand2; } else if (operand2 is double) { return (UInt64)operand1 % (double)operand2; } else if (operand2 is UInt64) { return (UInt64)operand1 % (UInt64)operand2; } } break; } throw new UberScriptException("Calculate MathNode did not have an assigned OpType!: value=" + node.Value); }