461 lines
13 KiB
C#
461 lines
13 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
|
|
namespace System.Linq.Expressions
|
|
{
|
|
/// <summary>Represents an expression that has a unary operator.</summary>
|
|
// Token: 0x02000030 RID: 48
|
|
public sealed class UnaryExpression : Expression
|
|
{
|
|
// Token: 0x06000251 RID: 593 RVA: 0x0000C180 File Offset: 0x0000A380
|
|
internal UnaryExpression(ExpressionType node_type, Expression operand, Type type)
|
|
: base(node_type, type)
|
|
{
|
|
this.operand = operand;
|
|
}
|
|
|
|
// Token: 0x06000252 RID: 594 RVA: 0x0000C194 File Offset: 0x0000A394
|
|
internal UnaryExpression(ExpressionType node_type, Expression operand, Type type, MethodInfo method, bool is_lifted)
|
|
: base(node_type, type)
|
|
{
|
|
this.operand = operand;
|
|
this.method = method;
|
|
this.is_lifted = is_lifted;
|
|
}
|
|
|
|
/// <summary>Gets the operand of the unary operation.</summary>
|
|
/// <returns>An <see cref="T:System.Linq.Expressions.Expression" /> that represents the operand of the unary operation.</returns>
|
|
// Token: 0x17000036 RID: 54
|
|
// (get) Token: 0x06000253 RID: 595 RVA: 0x0000C1B8 File Offset: 0x0000A3B8
|
|
public Expression Operand
|
|
{
|
|
get
|
|
{
|
|
return this.operand;
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets the implementing method for the unary operation.</summary>
|
|
/// <returns>The <see cref="T:System.Reflection.MethodInfo" /> that represents the implementing method.</returns>
|
|
// Token: 0x17000037 RID: 55
|
|
// (get) Token: 0x06000254 RID: 596 RVA: 0x0000C1C0 File Offset: 0x0000A3C0
|
|
public MethodInfo Method
|
|
{
|
|
get
|
|
{
|
|
return this.method;
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets a value that indicates whether the expression tree node represents a lifted call to an operator.</summary>
|
|
/// <returns>true if the node represents a lifted call; otherwise, false.</returns>
|
|
// Token: 0x17000038 RID: 56
|
|
// (get) Token: 0x06000255 RID: 597 RVA: 0x0000C1C8 File Offset: 0x0000A3C8
|
|
public bool IsLifted
|
|
{
|
|
get
|
|
{
|
|
return this.is_lifted;
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets a value that indicates whether the expression tree node represents a lifted call to an operator whose return type is lifted to a nullable type.</summary>
|
|
/// <returns>true if the operator's return type is lifted to a nullable type; otherwise, false.</returns>
|
|
// Token: 0x17000039 RID: 57
|
|
// (get) Token: 0x06000256 RID: 598 RVA: 0x0000C1D0 File Offset: 0x0000A3D0
|
|
public bool IsLiftedToNull
|
|
{
|
|
get
|
|
{
|
|
return this.is_lifted && base.Type.IsNullable();
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000257 RID: 599 RVA: 0x0000C1EC File Offset: 0x0000A3EC
|
|
private void EmitArrayLength(EmitContext ec)
|
|
{
|
|
this.operand.Emit(ec);
|
|
ec.ig.Emit(OpCodes.Ldlen);
|
|
}
|
|
|
|
// Token: 0x06000258 RID: 600 RVA: 0x0000C20C File Offset: 0x0000A40C
|
|
private void EmitTypeAs(EmitContext ec)
|
|
{
|
|
Type type = base.Type;
|
|
ec.EmitIsInst(this.operand, type);
|
|
if (type.IsNullable())
|
|
{
|
|
ec.ig.Emit(OpCodes.Unbox_Any, type);
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000259 RID: 601 RVA: 0x0000C24C File Offset: 0x0000A44C
|
|
private void EmitLiftedUnary(EmitContext ec)
|
|
{
|
|
ILGenerator ig = ec.ig;
|
|
LocalBuilder localBuilder = ec.EmitStored(this.operand);
|
|
LocalBuilder localBuilder2 = ig.DeclareLocal(base.Type);
|
|
Label label = ig.DefineLabel();
|
|
Label label2 = ig.DefineLabel();
|
|
ec.EmitNullableHasValue(localBuilder);
|
|
ig.Emit(OpCodes.Brtrue, label);
|
|
ec.EmitNullableInitialize(localBuilder2);
|
|
ig.Emit(OpCodes.Br, label2);
|
|
ig.MarkLabel(label);
|
|
ec.EmitNullableGetValueOrDefault(localBuilder);
|
|
this.EmitUnaryOperator(ec);
|
|
ec.EmitNullableNew(base.Type);
|
|
ig.MarkLabel(label2);
|
|
}
|
|
|
|
// Token: 0x0600025A RID: 602 RVA: 0x0000C2DC File Offset: 0x0000A4DC
|
|
private void EmitUnaryOperator(EmitContext ec)
|
|
{
|
|
ILGenerator ig = ec.ig;
|
|
ExpressionType nodeType = base.NodeType;
|
|
switch (nodeType)
|
|
{
|
|
case ExpressionType.Negate:
|
|
ig.Emit(OpCodes.Neg);
|
|
break;
|
|
default:
|
|
if (nodeType != ExpressionType.Convert && nodeType != ExpressionType.ConvertChecked)
|
|
{
|
|
if (nodeType == ExpressionType.Not)
|
|
{
|
|
if (this.operand.Type.GetNotNullableType() == typeof(bool))
|
|
{
|
|
ig.Emit(OpCodes.Ldc_I4_0);
|
|
ig.Emit(OpCodes.Ceq);
|
|
}
|
|
else
|
|
{
|
|
ig.Emit(OpCodes.Not);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.EmitPrimitiveConversion(ec, this.operand.Type.GetNotNullableType(), base.Type.GetNotNullableType());
|
|
}
|
|
break;
|
|
case ExpressionType.NegateChecked:
|
|
ig.Emit(OpCodes.Ldc_I4_M1);
|
|
ig.Emit((!Expression.IsUnsigned(this.operand.Type)) ? OpCodes.Mul_Ovf : OpCodes.Mul_Ovf_Un);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Token: 0x0600025B RID: 603 RVA: 0x0000C3E4 File Offset: 0x0000A5E4
|
|
private void EmitConvert(EmitContext ec)
|
|
{
|
|
Type type = this.operand.Type;
|
|
Type type2 = base.Type;
|
|
if (type == type2)
|
|
{
|
|
this.operand.Emit(ec);
|
|
}
|
|
else if (type.IsNullable() && !type2.IsNullable())
|
|
{
|
|
this.EmitConvertFromNullable(ec);
|
|
}
|
|
else if (!type.IsNullable() && type2.IsNullable())
|
|
{
|
|
this.EmitConvertToNullable(ec);
|
|
}
|
|
else if (type.IsNullable() && type2.IsNullable())
|
|
{
|
|
this.EmitConvertFromNullableToNullable(ec);
|
|
}
|
|
else if (Expression.IsReferenceConversion(type, type2))
|
|
{
|
|
this.EmitCast(ec);
|
|
}
|
|
else
|
|
{
|
|
if (!Expression.IsPrimitiveConversion(type, type2))
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
this.EmitPrimitiveConversion(ec);
|
|
}
|
|
}
|
|
|
|
// Token: 0x0600025C RID: 604 RVA: 0x0000C4B8 File Offset: 0x0000A6B8
|
|
private void EmitConvertFromNullableToNullable(EmitContext ec)
|
|
{
|
|
this.EmitLiftedUnary(ec);
|
|
}
|
|
|
|
// Token: 0x0600025D RID: 605 RVA: 0x0000C4C4 File Offset: 0x0000A6C4
|
|
private void EmitConvertToNullable(EmitContext ec)
|
|
{
|
|
ec.Emit(this.operand);
|
|
if (this.IsUnBoxing())
|
|
{
|
|
this.EmitUnbox(ec);
|
|
return;
|
|
}
|
|
if (this.operand.Type != base.Type.GetNotNullableType())
|
|
{
|
|
this.EmitPrimitiveConversion(ec, this.operand.Type, base.Type.GetNotNullableType());
|
|
}
|
|
ec.EmitNullableNew(base.Type);
|
|
}
|
|
|
|
// Token: 0x0600025E RID: 606 RVA: 0x0000C534 File Offset: 0x0000A734
|
|
private void EmitConvertFromNullable(EmitContext ec)
|
|
{
|
|
if (this.IsBoxing())
|
|
{
|
|
ec.Emit(this.operand);
|
|
this.EmitBox(ec);
|
|
return;
|
|
}
|
|
ec.EmitCall(this.operand, this.operand.Type.GetMethod("get_Value"));
|
|
if (this.operand.Type.GetNotNullableType() != base.Type)
|
|
{
|
|
this.EmitPrimitiveConversion(ec, this.operand.Type.GetNotNullableType(), base.Type);
|
|
}
|
|
}
|
|
|
|
// Token: 0x0600025F RID: 607 RVA: 0x0000C5BC File Offset: 0x0000A7BC
|
|
private bool IsBoxing()
|
|
{
|
|
return this.operand.Type.IsValueType && !base.Type.IsValueType;
|
|
}
|
|
|
|
// Token: 0x06000260 RID: 608 RVA: 0x0000C5F0 File Offset: 0x0000A7F0
|
|
private void EmitBox(EmitContext ec)
|
|
{
|
|
ec.ig.Emit(OpCodes.Box, this.operand.Type);
|
|
}
|
|
|
|
// Token: 0x06000261 RID: 609 RVA: 0x0000C610 File Offset: 0x0000A810
|
|
private bool IsUnBoxing()
|
|
{
|
|
return !this.operand.Type.IsValueType && base.Type.IsValueType;
|
|
}
|
|
|
|
// Token: 0x06000262 RID: 610 RVA: 0x0000C640 File Offset: 0x0000A840
|
|
private void EmitUnbox(EmitContext ec)
|
|
{
|
|
ec.ig.Emit(OpCodes.Unbox_Any, base.Type);
|
|
}
|
|
|
|
// Token: 0x06000263 RID: 611 RVA: 0x0000C658 File Offset: 0x0000A858
|
|
private void EmitCast(EmitContext ec)
|
|
{
|
|
this.operand.Emit(ec);
|
|
if (this.IsBoxing())
|
|
{
|
|
this.EmitBox(ec);
|
|
}
|
|
else if (this.IsUnBoxing())
|
|
{
|
|
this.EmitUnbox(ec);
|
|
}
|
|
else
|
|
{
|
|
ec.ig.Emit(OpCodes.Castclass, base.Type);
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000264 RID: 612 RVA: 0x0000C6B8 File Offset: 0x0000A8B8
|
|
private void EmitPrimitiveConversion(EmitContext ec, bool is_unsigned, OpCode signed, OpCode unsigned, OpCode signed_checked, OpCode unsigned_checked)
|
|
{
|
|
if (base.NodeType != ExpressionType.ConvertChecked)
|
|
{
|
|
ec.ig.Emit((!is_unsigned) ? signed : unsigned);
|
|
}
|
|
else
|
|
{
|
|
ec.ig.Emit((!is_unsigned) ? signed_checked : unsigned_checked);
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000265 RID: 613 RVA: 0x0000C70C File Offset: 0x0000A90C
|
|
private void EmitPrimitiveConversion(EmitContext ec)
|
|
{
|
|
this.operand.Emit(ec);
|
|
this.EmitPrimitiveConversion(ec, this.operand.Type, base.Type);
|
|
}
|
|
|
|
// Token: 0x06000266 RID: 614 RVA: 0x0000C740 File Offset: 0x0000A940
|
|
private void EmitPrimitiveConversion(EmitContext ec, Type from, Type to)
|
|
{
|
|
bool flag = Expression.IsUnsigned(from);
|
|
switch (Type.GetTypeCode(to))
|
|
{
|
|
case TypeCode.SByte:
|
|
this.EmitPrimitiveConversion(ec, flag, OpCodes.Conv_I1, OpCodes.Conv_U1, OpCodes.Conv_Ovf_I1, OpCodes.Conv_Ovf_I1_Un);
|
|
return;
|
|
case TypeCode.Byte:
|
|
this.EmitPrimitiveConversion(ec, flag, OpCodes.Conv_I1, OpCodes.Conv_U1, OpCodes.Conv_Ovf_U1, OpCodes.Conv_Ovf_U1_Un);
|
|
return;
|
|
case TypeCode.Int16:
|
|
this.EmitPrimitiveConversion(ec, flag, OpCodes.Conv_I2, OpCodes.Conv_U2, OpCodes.Conv_Ovf_I2, OpCodes.Conv_Ovf_I2_Un);
|
|
return;
|
|
case TypeCode.UInt16:
|
|
this.EmitPrimitiveConversion(ec, flag, OpCodes.Conv_I2, OpCodes.Conv_U2, OpCodes.Conv_Ovf_U2, OpCodes.Conv_Ovf_U2_Un);
|
|
return;
|
|
case TypeCode.Int32:
|
|
this.EmitPrimitiveConversion(ec, flag, OpCodes.Conv_I4, OpCodes.Conv_U4, OpCodes.Conv_Ovf_I4, OpCodes.Conv_Ovf_I4_Un);
|
|
return;
|
|
case TypeCode.UInt32:
|
|
this.EmitPrimitiveConversion(ec, flag, OpCodes.Conv_I4, OpCodes.Conv_U4, OpCodes.Conv_Ovf_U4, OpCodes.Conv_Ovf_U4_Un);
|
|
return;
|
|
case TypeCode.Int64:
|
|
this.EmitPrimitiveConversion(ec, flag, OpCodes.Conv_I8, OpCodes.Conv_U8, OpCodes.Conv_Ovf_I8, OpCodes.Conv_Ovf_I8_Un);
|
|
return;
|
|
case TypeCode.UInt64:
|
|
this.EmitPrimitiveConversion(ec, flag, OpCodes.Conv_I8, OpCodes.Conv_U8, OpCodes.Conv_Ovf_U8, OpCodes.Conv_Ovf_U8_Un);
|
|
return;
|
|
case TypeCode.Single:
|
|
if (flag)
|
|
{
|
|
ec.ig.Emit(OpCodes.Conv_R_Un);
|
|
}
|
|
ec.ig.Emit(OpCodes.Conv_R4);
|
|
return;
|
|
case TypeCode.Double:
|
|
if (flag)
|
|
{
|
|
ec.ig.Emit(OpCodes.Conv_R_Un);
|
|
}
|
|
ec.ig.Emit(OpCodes.Conv_R8);
|
|
return;
|
|
default:
|
|
throw new NotImplementedException(base.Type.ToString());
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000267 RID: 615 RVA: 0x0000C8D8 File Offset: 0x0000AAD8
|
|
private void EmitArithmeticUnary(EmitContext ec)
|
|
{
|
|
if (!this.IsLifted)
|
|
{
|
|
this.operand.Emit(ec);
|
|
this.EmitUnaryOperator(ec);
|
|
}
|
|
else
|
|
{
|
|
this.EmitLiftedUnary(ec);
|
|
}
|
|
}
|
|
|
|
// Token: 0x06000268 RID: 616 RVA: 0x0000C910 File Offset: 0x0000AB10
|
|
private void EmitUserDefinedLiftedToNullOperator(EmitContext ec)
|
|
{
|
|
ILGenerator ig = ec.ig;
|
|
LocalBuilder localBuilder = ec.EmitStored(this.operand);
|
|
Label label = ig.DefineLabel();
|
|
Label label2 = ig.DefineLabel();
|
|
ec.EmitNullableHasValue(localBuilder);
|
|
ig.Emit(OpCodes.Brfalse, label);
|
|
ec.EmitNullableGetValueOrDefault(localBuilder);
|
|
ec.EmitCall(this.method);
|
|
ec.EmitNullableNew(base.Type);
|
|
ig.Emit(OpCodes.Br, label2);
|
|
ig.MarkLabel(label);
|
|
LocalBuilder localBuilder2 = ig.DeclareLocal(base.Type);
|
|
ec.EmitNullableInitialize(localBuilder2);
|
|
ig.MarkLabel(label2);
|
|
}
|
|
|
|
// Token: 0x06000269 RID: 617 RVA: 0x0000C9A4 File Offset: 0x0000ABA4
|
|
private void EmitUserDefinedLiftedOperator(EmitContext ec)
|
|
{
|
|
LocalBuilder localBuilder = ec.EmitStored(this.operand);
|
|
ec.EmitNullableGetValue(localBuilder);
|
|
ec.EmitCall(this.method);
|
|
}
|
|
|
|
// Token: 0x0600026A RID: 618 RVA: 0x0000C9D4 File Offset: 0x0000ABD4
|
|
private void EmitUserDefinedOperator(EmitContext ec)
|
|
{
|
|
if (!this.IsLifted)
|
|
{
|
|
ec.Emit(this.operand);
|
|
ec.EmitCall(this.method);
|
|
}
|
|
else if (this.IsLiftedToNull)
|
|
{
|
|
this.EmitUserDefinedLiftedToNullOperator(ec);
|
|
}
|
|
else
|
|
{
|
|
this.EmitUserDefinedLiftedOperator(ec);
|
|
}
|
|
}
|
|
|
|
// Token: 0x0600026B RID: 619 RVA: 0x0000CA28 File Offset: 0x0000AC28
|
|
private void EmitQuote(EmitContext ec)
|
|
{
|
|
ec.EmitScope();
|
|
ec.EmitReadGlobal(this.operand, typeof(Expression));
|
|
if (ec.HasHoistedLocals)
|
|
{
|
|
ec.EmitLoadHoistedLocalsStore();
|
|
}
|
|
else
|
|
{
|
|
ec.ig.Emit(OpCodes.Ldnull);
|
|
}
|
|
ec.EmitIsolateExpression();
|
|
}
|
|
|
|
// Token: 0x0600026C RID: 620 RVA: 0x0000CA80 File Offset: 0x0000AC80
|
|
internal override void Emit(EmitContext ec)
|
|
{
|
|
if (this.method != null)
|
|
{
|
|
this.EmitUserDefinedOperator(ec);
|
|
return;
|
|
}
|
|
ExpressionType nodeType = base.NodeType;
|
|
switch (nodeType)
|
|
{
|
|
case ExpressionType.Negate:
|
|
case ExpressionType.UnaryPlus:
|
|
case ExpressionType.NegateChecked:
|
|
case ExpressionType.Not:
|
|
this.EmitArithmeticUnary(ec);
|
|
return;
|
|
default:
|
|
if (nodeType == ExpressionType.Convert || nodeType == ExpressionType.ConvertChecked)
|
|
{
|
|
this.EmitConvert(ec);
|
|
return;
|
|
}
|
|
if (nodeType == ExpressionType.ArrayLength)
|
|
{
|
|
this.EmitArrayLength(ec);
|
|
return;
|
|
}
|
|
if (nodeType == ExpressionType.Quote)
|
|
{
|
|
this.EmitQuote(ec);
|
|
return;
|
|
}
|
|
if (nodeType != ExpressionType.TypeAs)
|
|
{
|
|
throw new NotImplementedException(base.NodeType.ToString());
|
|
}
|
|
this.EmitTypeAs(ec);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Token: 0x040000C0 RID: 192
|
|
private Expression operand;
|
|
|
|
// Token: 0x040000C1 RID: 193
|
|
private MethodInfo method;
|
|
|
|
// Token: 0x040000C2 RID: 194
|
|
private bool is_lifted;
|
|
}
|
|
}
|