object EvaluateBinaryOperatorExpression (ValueReference left, ICSharpCode.NRefactory.Ast.Expression rightExp, BinaryOperatorType oper, object data)
		{
			// Shortcut ops
			
			switch (oper) {
				case BinaryOperatorType.LogicalAnd: {
					object val = left.ObjectValue;
					if (!(val is bool))
						throw CreateParseError ("Left operand of logical And must be a boolean");
					if (!(bool)val)
						return LiteralValueReference.CreateObjectLiteral (ctx, name, false);
					ValueReference vr = (ValueReference) rightExp.AcceptVisitor (this, data);
					if (ctx.Adapter.GetTypeName (ctx, vr.Type) != "System.Boolean")
						throw CreateParseError ("Right operand of logical And must be a boolean");
					return vr;
				}
				case BinaryOperatorType.LogicalOr: {
					object val = left.ObjectValue;
					if (!(val is bool))
						throw CreateParseError ("Left operand of logical Or must be a boolean");
					if ((bool)val)
						return LiteralValueReference.CreateObjectLiteral (ctx, name, true);
					ValueReference vr = (ValueReference) rightExp.AcceptVisitor (this, data);
					if (ctx.Adapter.GetTypeName (ctx, vr.Type) != "System.Boolean")
						throw CreateParseError ("Right operand of logical Or must be a boolean");
					return vr;
				}
			}

			ValueReference right = (ValueReference) rightExp.AcceptVisitor (this, data);
			object targetVal1 = left.Value;
			object targetVal2 = right.Value;
			object val1 = left.ObjectValue;
			object val2 = right.ObjectValue;
			
			if (oper == BinaryOperatorType.Add || oper == BinaryOperatorType.Concat) {
				if (val1 is string || val2 is string) {
					if (!(val1 is string) && val1 != null)
						val1 = ctx.Adapter.CallToString (ctx, targetVal1);
					if (!(val2 is string) && val2 != null)
						val2 = ctx.Adapter.CallToString (ctx, targetVal2);
					return LiteralValueReference.CreateObjectLiteral (ctx, name, (string) val1 + (string) val2);
				}
			}
			
			if ((oper == BinaryOperatorType.ExclusiveOr) && (val1 is bool) && (val2 is bool))
				return LiteralValueReference.CreateObjectLiteral (ctx, name, (bool)val1 ^ (bool)val2);

			if ((val1 == null || !val1.GetType ().IsPrimitive) && (val2 == null || !val2.GetType ().IsPrimitive)) {
				switch (oper) {
					case BinaryOperatorType.Equality:
						if (val1 == null || val2 == null)
							return LiteralValueReference.CreateObjectLiteral (ctx, name, val1 == val2);
						return LiteralValueReference.CreateObjectLiteral (ctx, name, val1.Equals (val2));
					case BinaryOperatorType.InEquality:
						if (val1 == null || val2 == null)
							return LiteralValueReference.CreateObjectLiteral (ctx, name, val1 != val2);
						return LiteralValueReference.CreateObjectLiteral (ctx, name, !val1.Equals (val2));
					case BinaryOperatorType.ReferenceEquality:
						return LiteralValueReference.CreateObjectLiteral (ctx, name, val1 == val2);
					case BinaryOperatorType.ReferenceInequality:
						return LiteralValueReference.CreateObjectLiteral (ctx, name, val1 != val2);
					case BinaryOperatorType.Concat:
						throw CreateParseError ("Invalid binary operator.");
				}
			}
			
			if (val1 == null || val2 == null || (val1 is bool) || (val2 is bool))
				throw CreateParseError ("Invalid operands in binary operator");
			
			long v1, v2;
			object longType = ctx.Adapter.GetType (ctx, "System.Int64");
			
			try {
				object c1 = ctx.Adapter.Cast (ctx, targetVal1, longType);
				v1 = (long) ctx.Adapter.TargetObjectToObject (ctx, c1);
					
				object c2 = ctx.Adapter.Cast (ctx, targetVal2, longType);
				v2 = (long) ctx.Adapter.TargetObjectToObject (ctx, c2);
			} catch {
				throw CreateParseError ("Invalid operands in binary operator");
			}
			
			object res;
			
			switch (oper) {
				case BinaryOperatorType.Add: res = v1 + v2; break;
				case BinaryOperatorType.BitwiseAnd: res = v1 & v2; break;
				case BinaryOperatorType.BitwiseOr: res = v1 | v2; break;
				case BinaryOperatorType.ExclusiveOr: res = v1 ^ v2; break;
				case BinaryOperatorType.DivideInteger:
				case BinaryOperatorType.Divide: res = v1 / v2; break;
				case BinaryOperatorType.Modulus: res = v1 % v2; break;
				case BinaryOperatorType.Multiply: res = v1 * v2; break;
				case BinaryOperatorType.Power: res = v1 ^ v2; break;
				case BinaryOperatorType.ShiftLeft: res = v1 << (int)v2; break;
				case BinaryOperatorType.ShiftRight: res = v1 >> (int)v2; break;
				case BinaryOperatorType.Subtract: res = v1 - v2; break;
				case BinaryOperatorType.GreaterThan: res = v1 > v2; break;
				case BinaryOperatorType.GreaterThanOrEqual: res = v1 >= v2; break;
				case BinaryOperatorType.LessThan: res = v1 < v2; break;
				case BinaryOperatorType.LessThanOrEqual: res = v1 <= v2; break;
				case BinaryOperatorType.ReferenceEquality:
				case BinaryOperatorType.Equality: res = v1 == v2; break;
				case BinaryOperatorType.ReferenceInequality:
				case BinaryOperatorType.InEquality: res = v1 != v2; break;
				default: throw CreateParseError ("Invalid binary operator.");
			}
			
			if (!(res is bool))
				res = (long) Convert.ChangeType (res, GetCommonType (v1, v2));
			
			if (ctx.Adapter.IsEnum (ctx, targetVal1)) {
				object tval = ctx.Adapter.Cast (ctx, ctx.Adapter.CreateValue (ctx, res), ctx.Adapter.GetValueType (ctx, targetVal1));
				return LiteralValueReference.CreateTargetObjectLiteral (ctx, name, tval);
			}
			if (ctx.Adapter.IsEnum (ctx, targetVal2)) {
				object tval = ctx.Adapter.Cast (ctx, ctx.Adapter.CreateValue (ctx, res), ctx.Adapter.GetValueType (ctx, targetVal2));
				return LiteralValueReference.CreateTargetObjectLiteral (ctx, name, tval);
			}
			
			return LiteralValueReference.CreateObjectLiteral (ctx, name, res);
		}