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); }