Example #1
0
		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);
		}
Example #2
0
        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");
            }
        }
Example #3
0
        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");
            }
        }
Example #4
0
 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);
 }