public void Visit(BinaryExpression expression) { expression.LeftExpression.Accept(this); Builder.Append(' '); switch (expression.Type) { case BinaryExpressionType.And: Builder.Append("&&"); break; case BinaryExpressionType.Or: Builder.Append("||"); break; case BinaryExpressionType.NotEqual: Builder.Append("!="); break; case BinaryExpressionType.LesserOrEqual: Builder.Append("<="); break; case BinaryExpressionType.GreaterOrEqual: Builder.Append(">="); break; case BinaryExpressionType.Lesser: Builder.Append("<"); break; case BinaryExpressionType.Greater: Builder.Append(">"); break; case BinaryExpressionType.Equal: Builder.Append(""); break; case BinaryExpressionType.Minus: Builder.Append("-"); break; case BinaryExpressionType.Plus: Builder.Append("+"); break; case BinaryExpressionType.Modulo: Builder.Append("%"); break; case BinaryExpressionType.Div: Builder.Append("/"); break; case BinaryExpressionType.Times: Builder.Append("*"); break; case BinaryExpressionType.Pow: Builder.Append("**"); break; case BinaryExpressionType.BitwiseAnd: Builder.Append("&"); break; case BinaryExpressionType.BitwiseOr: Builder.Append("|"); break; case BinaryExpressionType.BitwiseXOr: Builder.Append("^"); break; case BinaryExpressionType.Same: Builder.Append("==="); break; case BinaryExpressionType.NotSame: Builder.Append("!==="); break; case BinaryExpressionType.LeftShift: Builder.Append("<<"); break; case BinaryExpressionType.RightShift: Builder.Append(">>"); break; case BinaryExpressionType.UnsignedRightShift: Builder.Append(">>>"); break; case BinaryExpressionType.InstanceOf: Builder.Append("instanceof"); break; case BinaryExpressionType.In: Builder.Append("in"); break; case BinaryExpressionType.Unknown: Builder.Append(" /* unknown */"); break; default: throw new ArgumentOutOfRangeException(); } Builder.Append(' '); expression.RightExpression.Accept(this); }
public void Visit(BinaryExpression expression) { JsInstance old = Result; // Evaluates the left expression and saves the value expression.LeftExpression.Accept(this); JsInstance left = Result; //prevents execution of the right hand side if false if (expression.Type == BinaryExpressionType.And && !left.ToBoolean()) { Result = left; return; } //prevents execution of the right hand side if true if (expression.Type == BinaryExpressionType.Or && left.ToBoolean()) { Result = left; return; } Result = null; // Evaluates the right expression and saves the value expression.RightExpression.Accept(this); JsInstance right = Result; Result = old; switch (expression.Type) { case BinaryExpressionType.And: if (left.ToBoolean()) { Result = right; } else { Result = JsBoolean.False; } break; case BinaryExpressionType.Or: if (left.ToBoolean()) { Result = left; } else { Result = right; } break; case BinaryExpressionType.Div: var rightNumber = right.ToNumber(); var leftNumber = left.ToNumber(); if (right == Global.NumberClass["NEGATIVE_INFINITY"] || right == Global.NumberClass["POSITIVE_INFINITY"]) { Result = new JsNumber(0); } else if (rightNumber == 0) { Result = leftNumber > 0 ? Global.NumberClass["POSITIVE_INFINITY"] : Global.NumberClass["NEGATIVE_INFINITY"]; } else { Result = Global.NumberClass.New(leftNumber / rightNumber); } break; case BinaryExpressionType.Equal: if (left == JsUndefined.Instance && right == JsUndefined.Instance || left == JsNull.Instance && right == JsNull.Instance) { Result = JsBoolean.True; } else { if (left == JsUndefined.Instance && right != JsUndefined.Instance || left == JsNull.Instance && right != JsNull.Instance) { Result = JsBoolean.False; } else if (left != JsUndefined.Instance && right == JsUndefined.Instance || left != JsNull.Instance && right == JsNull.Instance) { Result = JsBoolean.False; } else { if (left.Class == JsNumber.TYPEOF || left.Class == JsBoolean.TYPEOF || right.Class == JsNumber.TYPEOF || right.Class == JsBoolean.TYPEOF) { Result = Global.BooleanClass.New(left.ToNumber() == right.ToNumber()); } else if (left.Class == JsString.TYPEOF || right.Class == JsString.TYPEOF) { Result = Global.BooleanClass.New(left.ToString() == right.ToString()); } else if (left.Value != null) { Result = Global.BooleanClass.New(left.Value.Equals(right.Value)); } else { Result = Global.BooleanClass.New(left == right); } } } break; case BinaryExpressionType.Greater: // Use the type of the left operand to make the comparison Result = Global.BooleanClass.New(left.ToNumber() > right.ToNumber()); break; case BinaryExpressionType.GreaterOrEqual: // Use the type of the left operand to make the comparison Result = Global.BooleanClass.New(left.ToNumber() >= right.ToNumber()); break; case BinaryExpressionType.Lesser: // Use the type of the left operand to make the comparison Result = Global.BooleanClass.New(left.ToNumber() < right.ToNumber()); break; case BinaryExpressionType.LesserOrEqual: // Use the type of the left operand to make the comparison Result = Global.BooleanClass.New(left.ToNumber() <= right.ToNumber()); break; case BinaryExpressionType.Minus: Result = Global.NumberClass.New(left.ToNumber() - right.ToNumber()); break; case BinaryExpressionType.Modulo: if (right == Global.NumberClass["NEGATIVE_INFINITY"] || right == Global.NumberClass["POSITIVE_INFINITY"]) { Result = Global.NumberClass["POSITIVE_INFINITY"]; } else if (right.ToNumber() == 0) { Result = Global.NumberClass["NaN"]; } else { Result = Global.NumberClass.New(left.ToNumber() % right.ToNumber()); } break; case BinaryExpressionType.NotEqual: if (left == JsUndefined.Instance && right == JsUndefined.Instance || left == JsNull.Instance && right == JsNull.Instance) { Result = JsBoolean.False; } else { if (left == JsUndefined.Instance && right != JsUndefined.Instance || left == JsNull.Instance && right != JsNull.Instance) { Result = JsBoolean.True; } else if (left != JsUndefined.Instance && right == JsUndefined.Instance || left != JsNull.Instance && right == JsNull.Instance) { Result = JsBoolean.True; } else { Result = Global.BooleanClass.New(!left.Value.Equals(right.Value)); } } break; case BinaryExpressionType.Plus: if (left.Class == JsString.TYPEOF || right.Class == JsString.TYPEOF) { Result = Global.StringClass.New(String.Concat(left.ToString(), right.ToString())); } else { Result = Global.NumberClass.New(left.ToNumber() + right.ToNumber()); } break; case BinaryExpressionType.Times: Result = Global.NumberClass.New(left.ToNumber() * right.ToNumber()); break; case BinaryExpressionType.Pow: Result = Global.NumberClass.New(Math.Pow(left.ToNumber(), right.ToNumber())); break; case BinaryExpressionType.BitwiseAnd: Result = Global.NumberClass.New(Convert.ToUInt64(left.ToNumber()) & Convert.ToUInt64(right.ToNumber())); break; case BinaryExpressionType.BitwiseOr: Result = Global.NumberClass.New(Convert.ToUInt64(left.ToNumber()) | Convert.ToUInt64(right.ToNumber())); break; case BinaryExpressionType.BitwiseXOr: Result = Global.NumberClass.New(Convert.ToUInt64(left.ToNumber()) ^ Convert.ToUInt64(right.ToNumber())); break; case BinaryExpressionType.Same: // 11.9.6 The Strict Equality Comparison Algorithm if (left.Class != right.Class) { Result = JsBoolean.False; } else if (left.Class == JsUndefined.TYPEOF) { Result = JsBoolean.True; } else if (left.Class == JsNull.TYPEOF) { Result = JsBoolean.True; } else if (left.Class == JsNumber.TYPEOF) { if (left == Global.NumberClass["NaN"] || right == Global.NumberClass["NaN"]) { Result = JsBoolean.False; } else if (left.ToNumber() == right.ToNumber()) { Result = JsBoolean.True; } else Result = JsBoolean.False; } else if (left.Class == JsString.TYPEOF) { Result = new JsBoolean(left.ToString() == right.ToString()); } else if (left.Class == JsBoolean.TYPEOF) { Result = new JsBoolean(left.ToBoolean() == right.ToBoolean()); } else if (left == right) { Result = JsBoolean.True; } else { Result = JsBoolean.False; } break; case BinaryExpressionType.NotSame: new BinaryExpression(BinaryExpressionType.Same, expression.LeftExpression, expression.RightExpression).Accept(this); Result = new JsBoolean(!Result.ToBoolean()); break; case BinaryExpressionType.LeftShift: Result = Global.NumberClass.New(Convert.ToUInt64(left.ToNumber()) << Convert.ToUInt16(right.ToNumber())); break; case BinaryExpressionType.RightShift: Result = Global.NumberClass.New(Convert.ToUInt64(left.ToNumber()) >> Convert.ToUInt16(right.ToNumber())); break; case BinaryExpressionType.UnsignedRightShift: Result = Global.NumberClass.New(Convert.ToUInt64(left.ToNumber()) >> Convert.ToUInt16(right.ToNumber())); break; case BinaryExpressionType.InstanceOf: Result = new JsBoolean(left.Class == right.ToString()); break; case BinaryExpressionType.In: if (right is JsDictionaryObject) { ((JsDictionaryObject)right).HasProperty(left); } else { throw new JintException("Cannot apply 'in' operator to the specified member."); } break; default: throw new NotSupportedException("Unkown binary operator"); } }
public void Visit(BinaryExpression expression) { // Evaluates the left expression and saves the value expression.LeftExpression.Accept(this); EnsureIdentifierIsDefined(Result); JsInstance left = Result; //prevents execution of the right hand side if false if (expression.Type == BinaryExpressionType.And && !left.ToBoolean()) { Result = left; return; } //prevents execution of the right hand side if true if (expression.Type == BinaryExpressionType.Or && left.ToBoolean()) { Result = left; return; } // Evaluates the right expression and saves the value expression.RightExpression.Accept(this); EnsureIdentifierIsDefined(Result); JsInstance right = Result; int cmpResult; switch (expression.Type) { case BinaryExpressionType.And: if (left.ToBoolean()) { Result = right; } else { Result = Global.BooleanClass.False; } break; case BinaryExpressionType.Or: if (left.ToBoolean()) { Result = left; } else { Result = right; } break; case BinaryExpressionType.Div: var rightNumber = right.ToNumber(); var leftNumber = left.ToNumber(); if (right == Global.NumberClass["NEGATIVE_INFINITY"] || right == Global.NumberClass["POSITIVE_INFINITY"]) { Result = Global.NumberClass.New(0); } else if (rightNumber == 0) { Result = leftNumber > 0 ? Global.NumberClass["POSITIVE_INFINITY"] : Global.NumberClass["NEGATIVE_INFINITY"]; } else { Result = Global.NumberClass.New(leftNumber / rightNumber); } break; case BinaryExpressionType.Equal: Result = Compare(left, right); break; case BinaryExpressionType.Greater: Result = CompareTo(left,right,out cmpResult) && cmpResult > 0 ? Global.BooleanClass.True : Global.BooleanClass.False ; break; case BinaryExpressionType.GreaterOrEqual: Result = CompareTo(left, right, out cmpResult) && cmpResult >= 0 ? Global.BooleanClass.True : Global.BooleanClass.False; break; case BinaryExpressionType.Lesser: Result = CompareTo(left, right, out cmpResult) && cmpResult < 0 ? Global.BooleanClass.True : Global.BooleanClass.False; break; case BinaryExpressionType.LesserOrEqual: Result = CompareTo(left, right, out cmpResult) && cmpResult <= 0 ? Global.BooleanClass.True : Global.BooleanClass.False; break; case BinaryExpressionType.Minus: Result = Global.NumberClass.New(left.ToNumber() - right.ToNumber()); break; case BinaryExpressionType.Modulo: if (right == Global.NumberClass["NEGATIVE_INFINITY"] || right == Global.NumberClass["POSITIVE_INFINITY"]) { Result = Global.NumberClass["POSITIVE_INFINITY"]; } else if (right.ToNumber() == 0) { Result = Global.NumberClass["NaN"]; } else { Result = Global.NumberClass.New(left.ToNumber() % right.ToNumber()); } break; case BinaryExpressionType.NotEqual: Result = Global.BooleanClass.New(!Compare(left, right).ToBoolean()); break; case BinaryExpressionType.Plus: if (left.Class == JsInstance.CLASS_STRING || right.Class == JsInstance.CLASS_STRING) { Result = Global.StringClass.New(String.Concat(left.ToString(), right.ToString())); } else { Result = Global.NumberClass.New(left.ToNumber() + right.ToNumber()); } break; case BinaryExpressionType.Times: Result = Global.NumberClass.New(left.ToNumber() * right.ToNumber()); break; case BinaryExpressionType.Pow: Result = Global.NumberClass.New(Math.Pow(left.ToNumber(), right.ToNumber())); break; case BinaryExpressionType.BitwiseAnd: if (left == JsUndefined.Instance || right == JsUndefined.Instance) Result = Global.NumberClass.New(0); else Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber()) & Convert.ToInt64(right.ToNumber())); break; case BinaryExpressionType.BitwiseOr: if (left == JsUndefined.Instance) { if(right == JsUndefined.Instance) Result = Global.NumberClass.New(1); else Result = Global.NumberClass.New(Convert.ToInt64(right.ToNumber())); } else if (right == JsUndefined.Instance) Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber())); else Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber()) | Convert.ToInt64(right.ToNumber())); break; case BinaryExpressionType.BitwiseXOr: if (left == JsUndefined.Instance) { if(right == JsUndefined.Instance) Result = Global.NumberClass.New(1); else Result = Global.NumberClass.New(Convert.ToInt64(right.ToNumber())); } else if (right == JsUndefined.Instance) Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber())); else Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber()) ^ Convert.ToInt64(right.ToNumber())); break; case BinaryExpressionType.Same: // 11.9.6 The Strict Equality Comparison Algorithm if (left.Type != right.Type) { Result = Global.BooleanClass.False; } else if (left is JsUndefined) { Result = Global.BooleanClass.True; } else if (left is JsNull) { Result = Global.BooleanClass.True; } else if (left.Type == JsInstance.TYPE_NUMBER) { if (left == Global.NumberClass["NaN"] || right == Global.NumberClass["NaN"]) { Result = Global.BooleanClass.False; } else if (left.ToNumber() == right.ToNumber()) { Result = Global.BooleanClass.True; } else Result = Global.BooleanClass.False; } else if (left.Type == JsInstance.TYPE_STRING) { Result = Global.BooleanClass.New(left.ToString() == right.ToString()); } else if (left.Type == JsInstance.TYPE_BOOLEAN) { Result = Global.BooleanClass.New(left.ToBoolean() == right.ToBoolean()); } else if (left == right) { Result = Global.BooleanClass.True; } else { Result = Global.BooleanClass.False; } break; case BinaryExpressionType.NotSame: new BinaryExpression(BinaryExpressionType.Same, expression.LeftExpression, expression.RightExpression).Accept(this); Result = Global.BooleanClass.New(!Result.ToBoolean()); break; case BinaryExpressionType.LeftShift: if (left == JsUndefined.Instance) Result = Global.NumberClass.New(0); else if (right == JsUndefined.Instance) Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber())); else Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber()) << Convert.ToUInt16(right.ToNumber())); break; case BinaryExpressionType.RightShift: if (left == JsUndefined.Instance) Result = Global.NumberClass.New(0); else if (right == JsUndefined.Instance) Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber())); else Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber()) >> Convert.ToUInt16(right.ToNumber())); break; case BinaryExpressionType.UnsignedRightShift: if (left == JsUndefined.Instance) Result = Global.NumberClass.New(0); else if (right == JsUndefined.Instance) Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber())); else Result = Global.NumberClass.New(Convert.ToInt64(left.ToNumber()) >> Convert.ToUInt16(right.ToNumber())); break; case BinaryExpressionType.InstanceOf: { var func = right as JsFunction; var obj = left as JsObject; if (func == null) throw new JsException(Global.TypeErrorClass.New("Right argument should be a function: " + expression.RightExpression.ToString())); if (obj == null) throw new JsException(Global.TypeErrorClass.New("Left argument should be an object: " + expression.LeftExpression.ToString())); Result = Global.BooleanClass.New(func.HasInstance(obj)); } break; case BinaryExpressionType.In: if (right is ILiteral) { throw new JsException(Global.ErrorClass.New("Cannot apply 'in' operator to the specified member.")); } else { Result = Global.BooleanClass.New(((JsDictionaryObject)right).HasProperty(left)); } break; default: throw new NotSupportedException("Unkown binary operator"); } }
void Analyze(BinaryExpression Stmt) { SetCurrentLineAndCharNos(Stmt); if (Stmt.LeftExpression != null) Analyze(Stmt.LeftExpression); AddToJintStack(Stmt.Source, JintState.BinaryOperator, ""); if (Stmt.RightExpression != null) Analyze(Stmt.RightExpression); }