503 changed files with 35645 additions and 14199 deletions
@ -0,0 +1,76 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using ICSharpCode.Decompiler; |
||||||
|
|
||||||
|
namespace ICSharpCode.ILSpyAddIn |
||||||
|
{ |
||||||
|
sealed class DebuggerTextOutput : ITextOutput |
||||||
|
{ |
||||||
|
readonly ITextOutput output; |
||||||
|
|
||||||
|
public readonly List<MemberMapping> DebuggerMemberMappings = new List<MemberMapping>(); |
||||||
|
|
||||||
|
public DebuggerTextOutput(ITextOutput output) |
||||||
|
{ |
||||||
|
this.output = output; |
||||||
|
} |
||||||
|
|
||||||
|
public ICSharpCode.NRefactory.TextLocation Location { |
||||||
|
get { return output.Location; } |
||||||
|
} |
||||||
|
|
||||||
|
public void Indent() |
||||||
|
{ |
||||||
|
output.Indent(); |
||||||
|
} |
||||||
|
|
||||||
|
public void Unindent() |
||||||
|
{ |
||||||
|
output.Unindent(); |
||||||
|
} |
||||||
|
|
||||||
|
public void Write(char ch) |
||||||
|
{ |
||||||
|
output.Write(ch); |
||||||
|
} |
||||||
|
|
||||||
|
public void Write(string text) |
||||||
|
{ |
||||||
|
output.Write(text); |
||||||
|
} |
||||||
|
|
||||||
|
public void WriteLine() |
||||||
|
{ |
||||||
|
output.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
public void WriteDefinition(string text, object definition, bool isLocal) |
||||||
|
{ |
||||||
|
output.WriteDefinition(text, definition, isLocal); |
||||||
|
} |
||||||
|
|
||||||
|
public void WriteReference(string text, object reference, bool isLocal) |
||||||
|
{ |
||||||
|
output.WriteReference(text, reference, isLocal); |
||||||
|
} |
||||||
|
|
||||||
|
public void AddDebuggerMemberMapping(MemberMapping memberMapping) |
||||||
|
{ |
||||||
|
DebuggerMemberMappings.Add(memberMapping); |
||||||
|
output.AddDebuggerMemberMapping(memberMapping); |
||||||
|
} |
||||||
|
|
||||||
|
public void MarkFoldStart(string collapsedText, bool defaultCollapsed) |
||||||
|
{ |
||||||
|
output.MarkFoldStart(collapsedText, defaultCollapsed); |
||||||
|
} |
||||||
|
|
||||||
|
public void MarkFoldEnd() |
||||||
|
{ |
||||||
|
output.MarkFoldEnd(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Diagnostics; |
||||||
|
using ICSharpCode.Decompiler.ILAst; |
||||||
|
using ICSharpCode.NRefactory.CSharp; |
||||||
|
using Mono.Cecil; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Ast |
||||||
|
{ |
||||||
|
public class TypeInformation |
||||||
|
{ |
||||||
|
public readonly TypeReference InferredType; |
||||||
|
|
||||||
|
public TypeInformation(TypeReference inferredType) |
||||||
|
{ |
||||||
|
this.InferredType = inferredType; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class LdTokenAnnotation {} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Annotation that is applied to the body expression of an Expression.Lambda() call.
|
||||||
|
/// </summary>
|
||||||
|
public class ParameterDeclarationAnnotation |
||||||
|
{ |
||||||
|
public readonly List<ParameterDeclaration> Parameters = new List<ParameterDeclaration>(); |
||||||
|
|
||||||
|
public ParameterDeclarationAnnotation(ILExpression expr) |
||||||
|
{ |
||||||
|
Debug.Assert(expr.Code == ILCode.ExpressionTreeParameterDeclarations); |
||||||
|
for (int i = 0; i < expr.Arguments.Count - 1; i++) { |
||||||
|
ILExpression p = expr.Arguments[i]; |
||||||
|
// p looks like this:
|
||||||
|
// stloc(v, call(Expression::Parameter, call(Type::GetTypeFromHandle, ldtoken(...)), ldstr(...)))
|
||||||
|
ILVariable v = (ILVariable)p.Operand; |
||||||
|
TypeReference typeRef = (TypeReference)p.Arguments[0].Arguments[0].Arguments[0].Operand; |
||||||
|
string name = (string)p.Arguments[0].Arguments[1].Operand; |
||||||
|
Parameters.Add(new ParameterDeclaration(AstBuilder.ConvertType(typeRef), name).WithAnnotation(v)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Annotation that is applied to a LambdaExpression that was produced by an expression tree.
|
||||||
|
/// </summary>
|
||||||
|
public class ExpressionTreeLambdaAnnotation |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,109 @@ |
|||||||
|
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Linq; |
||||||
|
using System.Reflection; |
||||||
|
using ICSharpCode.NRefactory.CSharp; |
||||||
|
using ICSharpCode.NRefactory.PatternMatching; |
||||||
|
using Mono.Cecil; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Ast.Transforms |
||||||
|
{ |
||||||
|
sealed class TypePattern : Pattern |
||||||
|
{ |
||||||
|
readonly string ns; |
||||||
|
readonly string name; |
||||||
|
|
||||||
|
public TypePattern(Type type) |
||||||
|
{ |
||||||
|
this.ns = type.Namespace; |
||||||
|
this.name = type.Name; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool DoMatch(INode other, Match match) |
||||||
|
{ |
||||||
|
ComposedType ct = other as ComposedType; |
||||||
|
AstType o; |
||||||
|
if (ct != null && !ct.HasNullableSpecifier && ct.PointerRank == 0 && !ct.ArraySpecifiers.Any()) { |
||||||
|
// Special case: ILSpy sometimes produces a ComposedType but then removed all array specifiers
|
||||||
|
// from it. In that case, we need to look at the base type for the annotations.
|
||||||
|
o = ct.BaseType; |
||||||
|
} else { |
||||||
|
o = other as AstType; |
||||||
|
if (o == null) |
||||||
|
return false; |
||||||
|
} |
||||||
|
TypeReference tr = o.Annotation<TypeReference>(); |
||||||
|
return tr != null && tr.Namespace == ns && tr.Name == name; |
||||||
|
} |
||||||
|
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
return name; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sealed class LdTokenPattern : Pattern |
||||||
|
{ |
||||||
|
AnyNode childNode; |
||||||
|
|
||||||
|
public LdTokenPattern(string groupName) |
||||||
|
{ |
||||||
|
this.childNode = new AnyNode(groupName); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool DoMatch(INode other, Match match) |
||||||
|
{ |
||||||
|
InvocationExpression ie = other as InvocationExpression; |
||||||
|
if (ie != null && ie.Annotation<LdTokenAnnotation>() != null && ie.Arguments.Count == 1) { |
||||||
|
return childNode.DoMatch(ie.Arguments.Single(), match); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
return "ldtoken(...)"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// typeof-Pattern that applies on the expanded form of typeof (prior to ReplaceMethodCallsWithOperators)
|
||||||
|
/// </summary>
|
||||||
|
sealed class TypeOfPattern : Pattern |
||||||
|
{ |
||||||
|
INode childNode; |
||||||
|
|
||||||
|
public TypeOfPattern(string groupName) |
||||||
|
{ |
||||||
|
childNode = new TypePattern(typeof(Type)).ToType().Invoke( |
||||||
|
"GetTypeFromHandle", new TypeOfExpression(new AnyNode(groupName)).Member("TypeHandle")); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool DoMatch(INode other, Match match) |
||||||
|
{ |
||||||
|
return childNode.DoMatch(other, match); |
||||||
|
} |
||||||
|
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
return "typeof(...)"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,875 @@ |
|||||||
|
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.Linq; |
||||||
|
using System.Reflection; |
||||||
|
using ICSharpCode.Decompiler.ILAst; |
||||||
|
using ICSharpCode.NRefactory.CSharp; |
||||||
|
using ICSharpCode.NRefactory.PatternMatching; |
||||||
|
using Mono.Cecil; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Ast.Transforms |
||||||
|
{ |
||||||
|
public class ExpressionTreeConverter |
||||||
|
{ |
||||||
|
#region static TryConvert method
|
||||||
|
public static bool CouldBeExpressionTree(InvocationExpression expr) |
||||||
|
{ |
||||||
|
if (expr != null && expr.Arguments.Count == 2) { |
||||||
|
MethodReference mr = expr.Annotation<MethodReference>(); |
||||||
|
return mr != null && mr.Name == "Lambda" && mr.DeclaringType.FullName == "System.Linq.Expressions.Expression"; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public static Expression TryConvert(DecompilerContext context, Expression expr) |
||||||
|
{ |
||||||
|
Expression converted = new ExpressionTreeConverter(context).Convert(expr); |
||||||
|
if (converted != null) { |
||||||
|
converted.AddAnnotation(new ExpressionTreeLambdaAnnotation()); |
||||||
|
} |
||||||
|
return converted; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
readonly DecompilerContext context; |
||||||
|
Stack<LambdaExpression> activeLambdas = new Stack<LambdaExpression>(); |
||||||
|
|
||||||
|
private ExpressionTreeConverter(DecompilerContext context) |
||||||
|
{ |
||||||
|
this.context = context; |
||||||
|
} |
||||||
|
|
||||||
|
#region Main Convert method
|
||||||
|
Expression Convert(Expression expr) |
||||||
|
{ |
||||||
|
InvocationExpression invocation = expr as InvocationExpression; |
||||||
|
if (invocation != null) { |
||||||
|
MethodReference mr = invocation.Annotation<MethodReference>(); |
||||||
|
if (mr != null && mr.DeclaringType.FullName == "System.Linq.Expressions.Expression") { |
||||||
|
switch (mr.Name) { |
||||||
|
case "Add": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.Add, false); |
||||||
|
case "AddChecked": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.Add, true); |
||||||
|
case "AddAssign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Add, false); |
||||||
|
case "AddAssignChecked": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Add, true); |
||||||
|
case "And": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.BitwiseAnd); |
||||||
|
case "AndAlso": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.ConditionalAnd); |
||||||
|
case "AndAssign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.BitwiseAnd); |
||||||
|
case "ArrayAccess": |
||||||
|
case "ArrayIndex": |
||||||
|
return ConvertArrayIndex(invocation); |
||||||
|
case "ArrayLength": |
||||||
|
return ConvertArrayLength(invocation); |
||||||
|
case "Assign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Assign); |
||||||
|
case "Call": |
||||||
|
return ConvertCall(invocation); |
||||||
|
case "Coalesce": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.NullCoalescing); |
||||||
|
case "Condition": |
||||||
|
return ConvertCondition(invocation); |
||||||
|
case "Constant": |
||||||
|
if (invocation.Arguments.Count >= 1) |
||||||
|
return invocation.Arguments.First().Clone(); |
||||||
|
else |
||||||
|
return NotSupported(expr); |
||||||
|
case "Convert": |
||||||
|
return ConvertCast(invocation, false); |
||||||
|
case "ConvertChecked": |
||||||
|
return ConvertCast(invocation, true); |
||||||
|
case "Divide": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.Divide); |
||||||
|
case "DivideAssign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Divide); |
||||||
|
case "Equal": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.Equality); |
||||||
|
case "ExclusiveOr": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.ExclusiveOr); |
||||||
|
case "ExclusiveOrAssign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.ExclusiveOr); |
||||||
|
case "Field": |
||||||
|
return ConvertField(invocation); |
||||||
|
case "GreaterThan": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.GreaterThan); |
||||||
|
case "GreaterThanOrEqual": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.GreaterThanOrEqual); |
||||||
|
case "Invoke": |
||||||
|
return ConvertInvoke(invocation); |
||||||
|
case "Lambda": |
||||||
|
return ConvertLambda(invocation); |
||||||
|
case "LeftShift": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.ShiftLeft); |
||||||
|
case "LeftShiftAssign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.ShiftLeft); |
||||||
|
case "LessThan": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.LessThan); |
||||||
|
case "LessThanOrEqual": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.LessThanOrEqual); |
||||||
|
case "ListInit": |
||||||
|
return ConvertListInit(invocation); |
||||||
|
case "MemberInit": |
||||||
|
return ConvertMemberInit(invocation); |
||||||
|
case "Modulo": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.Modulus); |
||||||
|
case "ModuloAssign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Modulus); |
||||||
|
case "Multiply": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.Multiply, false); |
||||||
|
case "MultiplyChecked": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.Multiply, true); |
||||||
|
case "MultiplyAssign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Multiply, false); |
||||||
|
case "MultiplyAssignChecked": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Multiply, true); |
||||||
|
case "Negate": |
||||||
|
return ConvertUnaryOperator(invocation, UnaryOperatorType.Minus, false); |
||||||
|
case "NegateChecked": |
||||||
|
return ConvertUnaryOperator(invocation, UnaryOperatorType.Minus, true); |
||||||
|
case "New": |
||||||
|
return ConvertNewObject(invocation); |
||||||
|
case "NewArrayBounds": |
||||||
|
return ConvertNewArrayBounds(invocation); |
||||||
|
case "NewArrayInit": |
||||||
|
return ConvertNewArrayInit(invocation); |
||||||
|
case "Not": |
||||||
|
return ConvertUnaryOperator(invocation, UnaryOperatorType.Not); |
||||||
|
case "NotEqual": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.InEquality); |
||||||
|
case "OnesComplement": |
||||||
|
return ConvertUnaryOperator(invocation, UnaryOperatorType.BitNot); |
||||||
|
case "Or": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.BitwiseOr); |
||||||
|
case "OrAssign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.BitwiseOr); |
||||||
|
case "OrElse": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.ConditionalOr); |
||||||
|
case "Property": |
||||||
|
return ConvertProperty(invocation); |
||||||
|
case "Quote": |
||||||
|
if (invocation.Arguments.Count == 1) |
||||||
|
return Convert(invocation.Arguments.Single()); |
||||||
|
else |
||||||
|
return NotSupported(invocation); |
||||||
|
case "RightShift": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.ShiftRight); |
||||||
|
case "RightShiftAssign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.ShiftRight); |
||||||
|
case "Subtract": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.Subtract, false); |
||||||
|
case "SubtractChecked": |
||||||
|
return ConvertBinaryOperator(invocation, BinaryOperatorType.Subtract, true); |
||||||
|
case "SubtractAssign": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Subtract, false); |
||||||
|
case "SubtractAssignChecked": |
||||||
|
return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Subtract, true); |
||||||
|
case "TypeAs": |
||||||
|
return ConvertTypeAs(invocation); |
||||||
|
case "TypeIs": |
||||||
|
return ConvertTypeIs(invocation); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
IdentifierExpression ident = expr as IdentifierExpression; |
||||||
|
if (ident != null) { |
||||||
|
ILVariable v = ident.Annotation<ILVariable>(); |
||||||
|
if (v != null) { |
||||||
|
foreach (LambdaExpression lambda in activeLambdas) { |
||||||
|
foreach (ParameterDeclaration p in lambda.Parameters) { |
||||||
|
if (p.Annotation<ILVariable>() == v) |
||||||
|
return new IdentifierExpression(p.Name).WithAnnotation(v); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return NotSupported(expr); |
||||||
|
} |
||||||
|
|
||||||
|
Expression NotSupported(Expression expr) |
||||||
|
{ |
||||||
|
Debug.WriteLine("Expression Tree Conversion Failed: '" + expr + "' is not supported"); |
||||||
|
return null; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert Lambda
|
||||||
|
static readonly Expression emptyArrayPattern = new ArrayCreateExpression { |
||||||
|
Type = new AnyNode(), |
||||||
|
Arguments = { new PrimitiveExpression(0) } |
||||||
|
}; |
||||||
|
|
||||||
|
Expression ConvertLambda(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
LambdaExpression lambda = new LambdaExpression(); |
||||||
|
Expression body = invocation.Arguments.First(); |
||||||
|
ArrayCreateExpression parameterArray = invocation.Arguments.Last() as ArrayCreateExpression; |
||||||
|
if (parameterArray == null) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
var annotation = body.Annotation<ParameterDeclarationAnnotation>(); |
||||||
|
if (annotation != null) { |
||||||
|
lambda.Parameters.AddRange(annotation.Parameters); |
||||||
|
} else { |
||||||
|
// No parameter declaration annotation found.
|
||||||
|
if (!emptyArrayPattern.IsMatch(parameterArray)) |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
activeLambdas.Push(lambda); |
||||||
|
Expression convertedBody = Convert(body); |
||||||
|
activeLambdas.Pop(); |
||||||
|
if (convertedBody == null) |
||||||
|
return null; |
||||||
|
lambda.Body = convertedBody; |
||||||
|
return lambda; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert Field
|
||||||
|
static readonly Expression getFieldFromHandlePattern = |
||||||
|
new TypePattern(typeof(FieldInfo)).ToType().Invoke( |
||||||
|
"GetFieldFromHandle", |
||||||
|
new LdTokenPattern("field").ToExpression().Member("FieldHandle"), |
||||||
|
new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle")) |
||||||
|
); |
||||||
|
|
||||||
|
Expression ConvertField(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
Expression fieldInfoExpr = invocation.Arguments.ElementAt(1); |
||||||
|
Match m = getFieldFromHandlePattern.Match(fieldInfoExpr); |
||||||
|
if (!m.Success) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
FieldReference fr = m.Get<AstNode>("field").Single().Annotation<FieldReference>(); |
||||||
|
if (fr == null) |
||||||
|
return null; |
||||||
|
|
||||||
|
Expression target = invocation.Arguments.ElementAt(0); |
||||||
|
Expression convertedTarget; |
||||||
|
if (target is NullReferenceExpression) { |
||||||
|
if (m.Has("declaringType")) |
||||||
|
convertedTarget = new TypeReferenceExpression(m.Get<AstType>("declaringType").Single().Clone()); |
||||||
|
else |
||||||
|
convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(fr.DeclaringType)); |
||||||
|
} else { |
||||||
|
convertedTarget = Convert(target); |
||||||
|
if (convertedTarget == null) |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return convertedTarget.Member(fr.Name).WithAnnotation(fr); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert Property
|
||||||
|
static readonly Expression getMethodFromHandlePattern = |
||||||
|
new TypePattern(typeof(MethodBase)).ToType().Invoke( |
||||||
|
"GetMethodFromHandle", |
||||||
|
new LdTokenPattern("method").ToExpression().Member("MethodHandle"), |
||||||
|
new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle")) |
||||||
|
).CastTo(new TypePattern(typeof(MethodInfo))); |
||||||
|
|
||||||
|
Expression ConvertProperty(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1)); |
||||||
|
if (!m.Success) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
MethodReference mr = m.Get<AstNode>("method").Single().Annotation<MethodReference>(); |
||||||
|
if (mr == null) |
||||||
|
return null; |
||||||
|
|
||||||
|
Expression target = invocation.Arguments.ElementAt(0); |
||||||
|
Expression convertedTarget; |
||||||
|
if (target is NullReferenceExpression) { |
||||||
|
if (m.Has("declaringType")) |
||||||
|
convertedTarget = new TypeReferenceExpression(m.Get<AstType>("declaringType").Single().Clone()); |
||||||
|
else |
||||||
|
convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(mr.DeclaringType)); |
||||||
|
} else { |
||||||
|
convertedTarget = Convert(target); |
||||||
|
if (convertedTarget == null) |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return convertedTarget.Member(GetPropertyName(mr)).WithAnnotation(mr); |
||||||
|
} |
||||||
|
|
||||||
|
string GetPropertyName(MethodReference accessor) |
||||||
|
{ |
||||||
|
string name = accessor.Name; |
||||||
|
if (name.StartsWith("get_", StringComparison.Ordinal) || name.StartsWith("set_", StringComparison.Ordinal)) |
||||||
|
name = name.Substring(4); |
||||||
|
return name; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert Call
|
||||||
|
Expression ConvertCall(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count < 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
Expression target; |
||||||
|
int firstArgumentPosition; |
||||||
|
|
||||||
|
Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(0)); |
||||||
|
if (m.Success) { |
||||||
|
target = null; |
||||||
|
firstArgumentPosition = 1; |
||||||
|
} else { |
||||||
|
m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1)); |
||||||
|
if (!m.Success) |
||||||
|
return NotSupported(invocation); |
||||||
|
target = invocation.Arguments.ElementAt(0); |
||||||
|
firstArgumentPosition = 2; |
||||||
|
} |
||||||
|
|
||||||
|
MethodReference mr = m.Get<AstNode>("method").Single().Annotation<MethodReference>(); |
||||||
|
if (mr == null) |
||||||
|
return null; |
||||||
|
|
||||||
|
Expression convertedTarget; |
||||||
|
if (target == null || target is NullReferenceExpression) { |
||||||
|
// static method
|
||||||
|
if (m.Has("declaringType")) |
||||||
|
convertedTarget = new TypeReferenceExpression(m.Get<AstType>("declaringType").Single().Clone()); |
||||||
|
else |
||||||
|
convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(mr.DeclaringType)); |
||||||
|
} else { |
||||||
|
convertedTarget = Convert(target); |
||||||
|
if (convertedTarget == null) |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
MemberReferenceExpression mre = convertedTarget.Member(mr.Name); |
||||||
|
GenericInstanceMethod gim = mr as GenericInstanceMethod; |
||||||
|
if (gim != null) { |
||||||
|
foreach (TypeReference tr in gim.GenericArguments) { |
||||||
|
mre.TypeArguments.Add(AstBuilder.ConvertType(tr)); |
||||||
|
} |
||||||
|
} |
||||||
|
IList<Expression> arguments = null; |
||||||
|
if (invocation.Arguments.Count == firstArgumentPosition + 1) { |
||||||
|
Expression argumentArray = invocation.Arguments.ElementAt(firstArgumentPosition); |
||||||
|
arguments = ConvertExpressionsArray(argumentArray); |
||||||
|
} |
||||||
|
if (arguments == null) { |
||||||
|
arguments = new List<Expression>(); |
||||||
|
foreach (Expression argument in invocation.Arguments.Skip(firstArgumentPosition)) { |
||||||
|
Expression convertedArgument = Convert(argument); |
||||||
|
if (convertedArgument == null) |
||||||
|
return null; |
||||||
|
arguments.Add(convertedArgument); |
||||||
|
} |
||||||
|
} |
||||||
|
MethodDefinition methodDef = mr.Resolve(); |
||||||
|
if (methodDef != null && methodDef.IsGetter) { |
||||||
|
PropertyDefinition indexer = AstMethodBodyBuilder.GetIndexer(methodDef); |
||||||
|
if (indexer != null) |
||||||
|
return new IndexerExpression(mre.Target.Detach(), arguments).WithAnnotation(indexer); |
||||||
|
} |
||||||
|
return new InvocationExpression(mre, arguments).WithAnnotation(mr); |
||||||
|
} |
||||||
|
|
||||||
|
Expression ConvertInvoke(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
Expression convertedTarget = Convert(invocation.Arguments.ElementAt(0)); |
||||||
|
IList<Expression> convertedArguments = ConvertExpressionsArray(invocation.Arguments.ElementAt(1)); |
||||||
|
if (convertedTarget != null && convertedArguments != null) |
||||||
|
return new InvocationExpression(convertedTarget, convertedArguments); |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert Binary Operator
|
||||||
|
static readonly Pattern trueOrFalse = new Choice { |
||||||
|
new PrimitiveExpression(true), |
||||||
|
new PrimitiveExpression(false) |
||||||
|
}; |
||||||
|
|
||||||
|
Expression ConvertBinaryOperator(InvocationExpression invocation, BinaryOperatorType op, bool? isChecked = null) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count < 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
Expression left = Convert(invocation.Arguments.ElementAt(0)); |
||||||
|
if (left == null) |
||||||
|
return null; |
||||||
|
Expression right = Convert(invocation.Arguments.ElementAt(1)); |
||||||
|
if (right == null) |
||||||
|
return null; |
||||||
|
|
||||||
|
BinaryOperatorExpression boe = new BinaryOperatorExpression(left, op, right); |
||||||
|
if (isChecked != null) |
||||||
|
boe.AddAnnotation(isChecked.Value ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); |
||||||
|
|
||||||
|
switch (invocation.Arguments.Count) { |
||||||
|
case 2: |
||||||
|
return boe; |
||||||
|
case 3: |
||||||
|
Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(2)); |
||||||
|
if (m.Success) |
||||||
|
return boe.WithAnnotation(m.Get<AstNode>("method").Single().Annotation<MethodReference>()); |
||||||
|
else |
||||||
|
return null; |
||||||
|
case 4: |
||||||
|
if (!trueOrFalse.IsMatch(invocation.Arguments.ElementAt(2))) |
||||||
|
return null; |
||||||
|
m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(3)); |
||||||
|
if (m.Success) |
||||||
|
return boe.WithAnnotation(m.Get<AstNode>("method").Single().Annotation<MethodReference>()); |
||||||
|
else |
||||||
|
return null; |
||||||
|
default: |
||||||
|
return NotSupported(invocation); |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert Assignment Operator
|
||||||
|
Expression ConvertAssignmentOperator(InvocationExpression invocation, AssignmentOperatorType op, bool? isChecked = null) |
||||||
|
{ |
||||||
|
return NotSupported(invocation); |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert Unary Operator
|
||||||
|
Expression ConvertUnaryOperator(InvocationExpression invocation, UnaryOperatorType op, bool? isChecked = null) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count < 1) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
Expression expr = Convert(invocation.Arguments.ElementAt(0)); |
||||||
|
if (expr == null) |
||||||
|
return null; |
||||||
|
|
||||||
|
UnaryOperatorExpression uoe = new UnaryOperatorExpression(op, expr); |
||||||
|
if (isChecked != null) |
||||||
|
uoe.AddAnnotation(isChecked.Value ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); |
||||||
|
|
||||||
|
switch (invocation.Arguments.Count) { |
||||||
|
case 1: |
||||||
|
return uoe; |
||||||
|
case 2: |
||||||
|
Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1)); |
||||||
|
if (m.Success) |
||||||
|
return uoe.WithAnnotation(m.Get<AstNode>("method").Single().Annotation<MethodReference>()); |
||||||
|
else |
||||||
|
return null; |
||||||
|
default: |
||||||
|
return NotSupported(invocation); |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert Condition Operator
|
||||||
|
Expression ConvertCondition(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 3) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
Expression condition = Convert(invocation.Arguments.ElementAt(0)); |
||||||
|
Expression trueExpr = Convert(invocation.Arguments.ElementAt(1)); |
||||||
|
Expression falseExpr = Convert(invocation.Arguments.ElementAt(2)); |
||||||
|
if (condition != null && trueExpr != null && falseExpr != null) |
||||||
|
return new ConditionalExpression(condition, trueExpr, falseExpr); |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert New Object
|
||||||
|
static readonly Expression newObjectCtorPattern = new TypePattern(typeof(MethodBase)).ToType().Invoke |
||||||
|
( |
||||||
|
"GetMethodFromHandle", |
||||||
|
new LdTokenPattern("ctor").ToExpression().Member("MethodHandle"), |
||||||
|
new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle")) |
||||||
|
).CastTo(new TypePattern(typeof(ConstructorInfo))); |
||||||
|
|
||||||
|
Expression ConvertNewObject(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count < 1 || invocation.Arguments.Count > 3) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
Match m = newObjectCtorPattern.Match(invocation.Arguments.First()); |
||||||
|
if (!m.Success) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
MethodReference ctor = m.Get<AstNode>("ctor").Single().Annotation<MethodReference>(); |
||||||
|
if (ctor == null) |
||||||
|
return null; |
||||||
|
|
||||||
|
AstType declaringTypeNode; |
||||||
|
TypeReference declaringType; |
||||||
|
if (m.Has("declaringType")) { |
||||||
|
declaringTypeNode = m.Get<AstType>("declaringType").Single().Clone(); |
||||||
|
declaringType = declaringTypeNode.Annotation<TypeReference>(); |
||||||
|
} else { |
||||||
|
declaringTypeNode = AstBuilder.ConvertType(ctor.DeclaringType); |
||||||
|
declaringType = ctor.DeclaringType; |
||||||
|
} |
||||||
|
if (declaringTypeNode == null) |
||||||
|
return null; |
||||||
|
|
||||||
|
ObjectCreateExpression oce = new ObjectCreateExpression(declaringTypeNode); |
||||||
|
if (invocation.Arguments.Count >= 2) { |
||||||
|
IList<Expression> arguments = ConvertExpressionsArray(invocation.Arguments.ElementAtOrDefault(1)); |
||||||
|
if (arguments == null) |
||||||
|
return null; |
||||||
|
oce.Arguments.AddRange(arguments); |
||||||
|
} |
||||||
|
if (invocation.Arguments.Count >= 3 && declaringType.IsAnonymousType()) { |
||||||
|
MethodDefinition resolvedCtor = ctor.Resolve(); |
||||||
|
if (resolvedCtor == null || resolvedCtor.Parameters.Count != oce.Arguments.Count) |
||||||
|
return null; |
||||||
|
AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression(); |
||||||
|
var arguments = oce.Arguments.ToArray(); |
||||||
|
if (AstMethodBodyBuilder.CanInferAnonymousTypePropertyNamesFromArguments(arguments, resolvedCtor.Parameters)) { |
||||||
|
oce.Arguments.MoveTo(atce.Initializers); |
||||||
|
} else { |
||||||
|
for (int i = 0; i < resolvedCtor.Parameters.Count; i++) { |
||||||
|
atce.Initializers.Add( |
||||||
|
new NamedExpression { |
||||||
|
Identifier = resolvedCtor.Parameters[i].Name, |
||||||
|
Expression = arguments[i].Detach() |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
return atce; |
||||||
|
} |
||||||
|
|
||||||
|
return oce; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert ListInit
|
||||||
|
static readonly Pattern elementInitArrayPattern = ArrayInitializationPattern( |
||||||
|
typeof(System.Linq.Expressions.ElementInit), |
||||||
|
new TypePattern(typeof(System.Linq.Expressions.Expression)).ToType().Invoke("ElementInit", new AnyNode("methodInfos"), new AnyNode("addArgumentsArrays")) |
||||||
|
); |
||||||
|
|
||||||
|
Expression ConvertListInit(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
ObjectCreateExpression oce = Convert(invocation.Arguments.ElementAt(0)) as ObjectCreateExpression; |
||||||
|
if (oce == null) |
||||||
|
return null; |
||||||
|
Expression elementsArray = invocation.Arguments.ElementAt(1); |
||||||
|
ArrayInitializerExpression initializer = ConvertElementInit(elementsArray); |
||||||
|
if (initializer != null) { |
||||||
|
oce.Initializer = initializer; |
||||||
|
return oce; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ArrayInitializerExpression ConvertElementInit(Expression elementsArray) |
||||||
|
{ |
||||||
|
IList<Expression> elements = ConvertExpressionsArray(elementsArray); |
||||||
|
if (elements != null) { |
||||||
|
return new ArrayInitializerExpression(elements); |
||||||
|
} |
||||||
|
Match m = elementInitArrayPattern.Match(elementsArray); |
||||||
|
if (!m.Success) |
||||||
|
return null; |
||||||
|
ArrayInitializerExpression result = new ArrayInitializerExpression(); |
||||||
|
foreach (var elementInit in m.Get<Expression>("addArgumentsArrays")) { |
||||||
|
IList<Expression> arguments = ConvertExpressionsArray(elementInit); |
||||||
|
if (arguments == null) |
||||||
|
return null; |
||||||
|
result.Elements.Add(new ArrayInitializerExpression(arguments)); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert MemberInit
|
||||||
|
Expression ConvertMemberInit(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
ObjectCreateExpression oce = Convert(invocation.Arguments.ElementAt(0)) as ObjectCreateExpression; |
||||||
|
if (oce == null) |
||||||
|
return null; |
||||||
|
Expression elementsArray = invocation.Arguments.ElementAt(1); |
||||||
|
ArrayInitializerExpression bindings = ConvertMemberBindings(elementsArray); |
||||||
|
if (bindings == null) |
||||||
|
return null; |
||||||
|
oce.Initializer = bindings; |
||||||
|
return oce; |
||||||
|
} |
||||||
|
|
||||||
|
static readonly Pattern memberBindingArrayPattern = ArrayInitializationPattern(typeof(System.Linq.Expressions.MemberBinding), new AnyNode("binding")); |
||||||
|
static readonly INode expressionTypeReference = new TypeReferenceExpression(new TypePattern(typeof(System.Linq.Expressions.Expression))); |
||||||
|
|
||||||
|
ArrayInitializerExpression ConvertMemberBindings(Expression elementsArray) |
||||||
|
{ |
||||||
|
Match m = memberBindingArrayPattern.Match(elementsArray); |
||||||
|
if (!m.Success) |
||||||
|
return null; |
||||||
|
ArrayInitializerExpression result = new ArrayInitializerExpression(); |
||||||
|
foreach (var binding in m.Get<Expression>("binding")) { |
||||||
|
InvocationExpression bindingInvocation = binding as InvocationExpression; |
||||||
|
if (bindingInvocation == null || bindingInvocation.Arguments.Count != 2) |
||||||
|
return null; |
||||||
|
MemberReferenceExpression bindingMRE = bindingInvocation.Target as MemberReferenceExpression; |
||||||
|
if (bindingMRE == null || !expressionTypeReference.IsMatch(bindingMRE.Target)) |
||||||
|
return null; |
||||||
|
|
||||||
|
Expression bindingTarget = bindingInvocation.Arguments.ElementAt(0); |
||||||
|
Expression bindingValue = bindingInvocation.Arguments.ElementAt(1); |
||||||
|
|
||||||
|
string memberName; |
||||||
|
Match m2 = getMethodFromHandlePattern.Match(bindingTarget); |
||||||
|
if (m2.Success) { |
||||||
|
MethodReference setter = m2.Get<AstNode>("method").Single().Annotation<MethodReference>(); |
||||||
|
if (setter == null) |
||||||
|
return null; |
||||||
|
memberName = GetPropertyName(setter); |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
Expression convertedValue; |
||||||
|
switch (bindingMRE.MemberName) { |
||||||
|
case "Bind": |
||||||
|
convertedValue = Convert(bindingValue); |
||||||
|
break; |
||||||
|
case "MemberBind": |
||||||
|
convertedValue = ConvertMemberBindings(bindingValue); |
||||||
|
break; |
||||||
|
case "ListBind": |
||||||
|
convertedValue = ConvertElementInit(bindingValue); |
||||||
|
break; |
||||||
|
default: |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (convertedValue == null) |
||||||
|
return null; |
||||||
|
result.Elements.Add(new NamedExpression(memberName, convertedValue)); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert Cast
|
||||||
|
Expression ConvertCast(InvocationExpression invocation, bool isChecked) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count < 2) |
||||||
|
return null; |
||||||
|
Expression converted = Convert(invocation.Arguments.ElementAt(0)); |
||||||
|
AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1)); |
||||||
|
if (converted != null && type != null) { |
||||||
|
CastExpression cast = converted.CastTo(type); |
||||||
|
cast.AddAnnotation(isChecked ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); |
||||||
|
switch (invocation.Arguments.Count) { |
||||||
|
case 2: |
||||||
|
return cast; |
||||||
|
case 3: |
||||||
|
Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(2)); |
||||||
|
if (m.Success) |
||||||
|
return cast.WithAnnotation(m.Get<AstNode>("method").Single().Annotation<MethodReference>()); |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ConvertExpressionsArray
|
||||||
|
static Pattern ArrayInitializationPattern(Type arrayElementType, INode elementPattern) |
||||||
|
{ |
||||||
|
return new Choice { |
||||||
|
new ArrayCreateExpression { |
||||||
|
Type = new TypePattern(arrayElementType), |
||||||
|
Arguments = { new PrimitiveExpression(0) } |
||||||
|
}, |
||||||
|
new ArrayCreateExpression { |
||||||
|
Type = new TypePattern(arrayElementType), |
||||||
|
AdditionalArraySpecifiers = { new ArraySpecifier() }, |
||||||
|
Initializer = new ArrayInitializerExpression { |
||||||
|
Elements = { new Repeat(elementPattern) } |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
static readonly Pattern expressionArrayPattern = ArrayInitializationPattern(typeof(System.Linq.Expressions.Expression), new AnyNode("elements")); |
||||||
|
|
||||||
|
IList<Expression> ConvertExpressionsArray(Expression arrayExpression) |
||||||
|
{ |
||||||
|
Match m = expressionArrayPattern.Match(arrayExpression); |
||||||
|
if (m.Success) { |
||||||
|
List<Expression> result = new List<Expression>(); |
||||||
|
foreach (Expression expr in m.Get<Expression>("elements")) { |
||||||
|
Expression converted = Convert(expr); |
||||||
|
if (converted == null) |
||||||
|
return null; |
||||||
|
result.Add(converted); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert TypeAs/TypeIs
|
||||||
|
static readonly TypeOfPattern typeOfPattern = new TypeOfPattern("type"); |
||||||
|
|
||||||
|
AstType ConvertTypeReference(Expression typeOfExpression) |
||||||
|
{ |
||||||
|
Match m = typeOfPattern.Match(typeOfExpression); |
||||||
|
if (m.Success) |
||||||
|
return m.Get<AstType>("type").Single().Clone(); |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
Expression ConvertTypeAs(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return null; |
||||||
|
Expression converted = Convert(invocation.Arguments.ElementAt(0)); |
||||||
|
AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1)); |
||||||
|
if (converted != null && type != null) |
||||||
|
return new AsExpression(converted, type); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
Expression ConvertTypeIs(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return null; |
||||||
|
Expression converted = Convert(invocation.Arguments.ElementAt(0)); |
||||||
|
AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1)); |
||||||
|
if (converted != null && type != null) |
||||||
|
return new IsExpression { Expression = converted, Type = type }; |
||||||
|
return null; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Convert Array
|
||||||
|
Expression ConvertArrayIndex(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
Expression targetConverted = Convert(invocation.Arguments.First()); |
||||||
|
if (targetConverted == null) |
||||||
|
return null; |
||||||
|
|
||||||
|
Expression index = invocation.Arguments.ElementAt(1); |
||||||
|
Expression indexConverted = Convert(index); |
||||||
|
if (indexConverted != null) { |
||||||
|
return new IndexerExpression(targetConverted, indexConverted); |
||||||
|
} |
||||||
|
IList<Expression> indexesConverted = ConvertExpressionsArray(index); |
||||||
|
if (indexConverted != null) { |
||||||
|
return new IndexerExpression(targetConverted, indexesConverted); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
Expression ConvertArrayLength(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 1) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
Expression targetConverted = Convert(invocation.Arguments.Single()); |
||||||
|
if (targetConverted != null) |
||||||
|
return targetConverted.Member("Length"); |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
Expression ConvertNewArrayInit(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
AstType elementType = ConvertTypeReference(invocation.Arguments.ElementAt(0)); |
||||||
|
IList<Expression> elements = ConvertExpressionsArray(invocation.Arguments.ElementAt(1)); |
||||||
|
if (elementType != null && elements != null) { |
||||||
|
if (ContainsAnonymousType(elementType)) { |
||||||
|
elementType = null; |
||||||
|
} |
||||||
|
return new ArrayCreateExpression { |
||||||
|
Type = elementType, |
||||||
|
AdditionalArraySpecifiers = { new ArraySpecifier() }, |
||||||
|
Initializer = new ArrayInitializerExpression(elements) |
||||||
|
}; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
Expression ConvertNewArrayBounds(InvocationExpression invocation) |
||||||
|
{ |
||||||
|
if (invocation.Arguments.Count != 2) |
||||||
|
return NotSupported(invocation); |
||||||
|
|
||||||
|
AstType elementType = ConvertTypeReference(invocation.Arguments.ElementAt(0)); |
||||||
|
IList<Expression> arguments = ConvertExpressionsArray(invocation.Arguments.ElementAt(1)); |
||||||
|
if (elementType != null && arguments != null) { |
||||||
|
if (ContainsAnonymousType(elementType)) { |
||||||
|
elementType = null; |
||||||
|
} |
||||||
|
ArrayCreateExpression ace = new ArrayCreateExpression(); |
||||||
|
ace.Type = elementType; |
||||||
|
ace.Arguments.AddRange(arguments); |
||||||
|
return ace; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
bool ContainsAnonymousType(AstType type) |
||||||
|
{ |
||||||
|
foreach (AstType t in type.DescendantsAndSelf.OfType<AstType>()) { |
||||||
|
TypeReference tr = t.Annotation<TypeReference>(); |
||||||
|
if (tr != null && tr.IsAnonymousType()) |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using ICSharpCode.NRefactory.CSharp; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Ast.Transforms |
||||||
|
{ |
||||||
|
class FlattenSwitchBlocks : IAstTransform |
||||||
|
{ |
||||||
|
public void Run(AstNode compilationUnit) |
||||||
|
{ |
||||||
|
foreach (var switchSection in compilationUnit.Descendants.OfType<SwitchSection>()) |
||||||
|
{ |
||||||
|
if (switchSection.Statements.Count != 1) |
||||||
|
continue; |
||||||
|
|
||||||
|
var blockStatement = switchSection.Statements.First() as BlockStatement; |
||||||
|
if (blockStatement == null || blockStatement.Statements.Any(st => st is VariableDeclarationStatement)) |
||||||
|
continue; |
||||||
|
|
||||||
|
blockStatement.Remove(); |
||||||
|
blockStatement.Statements.MoveTo(switchSection.Statements); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,528 @@ |
|||||||
|
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
|
||||||
|
using Mono.Cecil; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.ILAst |
||||||
|
{ |
||||||
|
partial class ILAstOptimizer |
||||||
|
{ |
||||||
|
bool SimplifyLiftedOperators(List<ILNode> body, ILExpression expr, int pos) |
||||||
|
{ |
||||||
|
if (!new PatternMatcher(typeSystem).SimplifyLiftedOperators(expr)) return false; |
||||||
|
|
||||||
|
var inlining = new ILInlining(method); |
||||||
|
while (--pos >= 0 && inlining.InlineIfPossible(body, ref pos)) ; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
sealed class PatternMatcher |
||||||
|
{ |
||||||
|
readonly TypeSystem typeSystem; |
||||||
|
public PatternMatcher(TypeSystem typeSystem) |
||||||
|
{ |
||||||
|
this.typeSystem = typeSystem; |
||||||
|
} |
||||||
|
|
||||||
|
public bool SimplifyLiftedOperators(ILExpression expr) |
||||||
|
{ |
||||||
|
if (Simplify(expr)) return true; |
||||||
|
|
||||||
|
bool modified = false; |
||||||
|
foreach (var a in expr.Arguments) |
||||||
|
modified |= SimplifyLiftedOperators(a); |
||||||
|
return modified; |
||||||
|
} |
||||||
|
|
||||||
|
abstract class Pattern |
||||||
|
{ |
||||||
|
public readonly Pattern[] Arguments; |
||||||
|
|
||||||
|
protected Pattern(Pattern[] arguments) |
||||||
|
{ |
||||||
|
this.Arguments = arguments; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual bool Match(PatternMatcher pm, ILExpression e) |
||||||
|
{ |
||||||
|
if (e.Arguments.Count != this.Arguments.Length || e.Prefixes != null) return false; |
||||||
|
for (int i = 0; i < this.Arguments.Length; i++) |
||||||
|
if (!this.Arguments[i].Match(pm, e.Arguments[i])) return false; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual ILExpression BuildNew(PatternMatcher pm) |
||||||
|
{ |
||||||
|
throw new NotSupportedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public static Pattern operator &(Pattern a, Pattern b) |
||||||
|
{ |
||||||
|
return new ILPattern(ILCode.LogicAnd, a, b); |
||||||
|
} |
||||||
|
|
||||||
|
public static Pattern operator |(Pattern a, Pattern b) |
||||||
|
{ |
||||||
|
return new ILPattern(ILCode.LogicOr, a, b); |
||||||
|
} |
||||||
|
|
||||||
|
public static Pattern operator !(Pattern a) |
||||||
|
{ |
||||||
|
return new ILPattern(ILCode.LogicNot, a); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sealed class ILPattern : Pattern |
||||||
|
{ |
||||||
|
readonly ILCode code; |
||||||
|
|
||||||
|
public ILPattern(ILCode code, params Pattern[] arguments) |
||||||
|
: base(arguments) |
||||||
|
{ |
||||||
|
this.code = code; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool Match(PatternMatcher pm, ILExpression e) |
||||||
|
{ |
||||||
|
return e.Code == this.code && base.Match(pm, e); |
||||||
|
} |
||||||
|
|
||||||
|
public override ILExpression BuildNew(PatternMatcher pm) |
||||||
|
{ |
||||||
|
var args = new ILExpression[this.Arguments.Length]; |
||||||
|
for (int i = 0; i < args.Length; i++) args[i] = this.Arguments[i].BuildNew(pm); |
||||||
|
TypeReference t = null; |
||||||
|
switch (code) { |
||||||
|
case ILCode.Ceq: |
||||||
|
case ILCode.Cne: |
||||||
|
t = pm.typeSystem.Boolean; |
||||||
|
break; |
||||||
|
case ILCode.NullCoalescing: |
||||||
|
t = args[1].InferredType; |
||||||
|
break; |
||||||
|
} |
||||||
|
return new ILExpression(code, null, args) { InferredType = t }; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sealed class MethodPattern : Pattern |
||||||
|
{ |
||||||
|
readonly ILCode code; |
||||||
|
readonly string method; |
||||||
|
|
||||||
|
public MethodPattern(ILCode code, string method, params Pattern[] arguments) |
||||||
|
: base(arguments) |
||||||
|
{ |
||||||
|
this.code = code; |
||||||
|
this.method = method; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool Match(PatternMatcher pm, ILExpression e) |
||||||
|
{ |
||||||
|
if (e.Code != this.code) return false; |
||||||
|
var m = (MethodReference)e.Operand; |
||||||
|
return m.Name == this.method && TypeAnalysis.IsNullableType(m.DeclaringType) && base.Match(pm, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
enum OperatorType |
||||||
|
{ |
||||||
|
Equality, InEquality, Comparison, Other |
||||||
|
} |
||||||
|
|
||||||
|
sealed class OperatorPattern : Pattern |
||||||
|
{ |
||||||
|
OperatorType type; |
||||||
|
bool simple; |
||||||
|
|
||||||
|
public OperatorPattern() : base(null) { } |
||||||
|
|
||||||
|
public OperatorPattern(OperatorType type, bool simple) |
||||||
|
: this() |
||||||
|
{ |
||||||
|
this.type = type; |
||||||
|
this.simple = simple; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool Match(PatternMatcher pm, ILExpression e) |
||||||
|
{ |
||||||
|
switch (e.Code) { |
||||||
|
case ILCode.Ceq: |
||||||
|
if (type != OperatorType.Equality) return false; |
||||||
|
break; |
||||||
|
case ILCode.Cne: |
||||||
|
if (type != OperatorType.InEquality) return false; |
||||||
|
break; |
||||||
|
case ILCode.Cgt: |
||||||
|
case ILCode.Cgt_Un: |
||||||
|
case ILCode.Cge: |
||||||
|
case ILCode.Cge_Un: |
||||||
|
case ILCode.Clt: |
||||||
|
case ILCode.Clt_Un: |
||||||
|
case ILCode.Cle: |
||||||
|
case ILCode.Cle_Un: |
||||||
|
if (type != OperatorType.Comparison) return false; |
||||||
|
break; |
||||||
|
case ILCode.Add: |
||||||
|
case ILCode.Add_Ovf: |
||||||
|
case ILCode.Add_Ovf_Un: |
||||||
|
case ILCode.Sub: |
||||||
|
case ILCode.Sub_Ovf: |
||||||
|
case ILCode.Sub_Ovf_Un: |
||||||
|
case ILCode.Mul: |
||||||
|
case ILCode.Mul_Ovf: |
||||||
|
case ILCode.Mul_Ovf_Un: |
||||||
|
case ILCode.Div: |
||||||
|
case ILCode.Div_Un: |
||||||
|
case ILCode.Rem: |
||||||
|
case ILCode.Rem_Un: |
||||||
|
case ILCode.And: |
||||||
|
case ILCode.Or: |
||||||
|
case ILCode.Xor: |
||||||
|
case ILCode.Shl: |
||||||
|
case ILCode.Shr: |
||||||
|
case ILCode.Shr_Un: |
||||||
|
case ILCode.Not: |
||||||
|
case ILCode.Neg: |
||||||
|
case ILCode.LogicNot: |
||||||
|
if (type != OperatorType.Other) return false; |
||||||
|
break; |
||||||
|
case ILCode.Call: |
||||||
|
var m = e.Operand as MethodReference; |
||||||
|
if (m == null || m.HasThis || !m.HasParameters || e.Arguments.Count > 2 || !IsCustomOperator(m.Name)) return false; |
||||||
|
break; |
||||||
|
default: return false; |
||||||
|
} |
||||||
|
if (pm.Operator != null) throw new InvalidOperationException(); |
||||||
|
pm.Operator = e; |
||||||
|
|
||||||
|
var a0 = e.Arguments[0]; |
||||||
|
if (!simple) return VariableAGetValueOrDefault.Match(pm, a0) && VariableBGetValueOrDefault.Match(pm, e.Arguments[1]); |
||||||
|
if (e.Arguments.Count == 1) return VariableAGetValueOrDefault.Match(pm, a0); |
||||||
|
if (VariableAGetValueOrDefault.Match(pm, a0)) { |
||||||
|
pm.SimpleOperand = e.Arguments[1]; |
||||||
|
pm.SimpleLeftOperand = false; |
||||||
|
return true; |
||||||
|
} |
||||||
|
if (VariableAGetValueOrDefault.Match(pm, e.Arguments[1])) { |
||||||
|
pm.SimpleOperand = a0; |
||||||
|
pm.SimpleLeftOperand = true; |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool IsCustomOperator(string s) |
||||||
|
{ |
||||||
|
switch (type) { |
||||||
|
case OperatorType.Equality: return s == "op_Equality"; |
||||||
|
case OperatorType.InEquality: return s == "op_Inequality"; |
||||||
|
case OperatorType.Comparison: |
||||||
|
if (s.Length < 11 || !s.StartsWith("op_", StringComparison.Ordinal)) return false; |
||||||
|
switch (s) { |
||||||
|
case "op_GreaterThan": |
||||||
|
case "op_GreaterThanOrEqual": |
||||||
|
case "op_LessThan": |
||||||
|
case "op_LessThanOrEqual": return true; |
||||||
|
default: return false; |
||||||
|
} |
||||||
|
default: |
||||||
|
if (s.Length < 10 || !s.StartsWith("op_", StringComparison.Ordinal)) return false; |
||||||
|
switch (s) { |
||||||
|
case "op_Addition": |
||||||
|
case "op_Subtraction": |
||||||
|
case "op_Multiply": |
||||||
|
case "op_Division": |
||||||
|
case "op_Modulus": |
||||||
|
case "op_BitwiseAnd": |
||||||
|
case "op_BitwiseOr": |
||||||
|
case "op_ExclusiveOr": |
||||||
|
case "op_LeftShift": |
||||||
|
case "op_RightShift": |
||||||
|
case "op_UnaryNegation": |
||||||
|
case "op_UnaryPlus": |
||||||
|
case "op_LogicalNot": |
||||||
|
case "op_OnesComplement": |
||||||
|
case "op_Increment": |
||||||
|
case "op_Decrement": return true; |
||||||
|
default: return false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override ILExpression BuildNew(PatternMatcher pm) |
||||||
|
{ |
||||||
|
var res = pm.Operator; |
||||||
|
res.Arguments.Clear(); |
||||||
|
if (pm.SimpleLeftOperand) res.Arguments.Add(pm.SimpleOperand); |
||||||
|
res.Arguments.Add(VariableA.BuildNew(pm)); |
||||||
|
if (pm.B != null) res.Arguments.Add(VariableB.BuildNew(pm)); |
||||||
|
else if (pm.SimpleOperand != null && !pm.SimpleLeftOperand) res.Arguments.Add(pm.SimpleOperand); |
||||||
|
return res; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sealed class AnyPattern : Pattern |
||||||
|
{ |
||||||
|
public AnyPattern() : base(null) { } |
||||||
|
|
||||||
|
public override bool Match(PatternMatcher pm, ILExpression e) |
||||||
|
{ |
||||||
|
if (pm.SimpleOperand != null) throw new InvalidOperationException(); |
||||||
|
pm.SimpleOperand = e; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override ILExpression BuildNew(PatternMatcher pm) |
||||||
|
{ |
||||||
|
return pm.SimpleOperand; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sealed class VariablePattern : Pattern |
||||||
|
{ |
||||||
|
readonly ILCode code; |
||||||
|
readonly bool b; |
||||||
|
|
||||||
|
public VariablePattern(ILCode code, bool b) |
||||||
|
: base(null) |
||||||
|
{ |
||||||
|
this.code = code; |
||||||
|
this.b = b; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool Match(PatternMatcher pm, ILExpression e) |
||||||
|
{ |
||||||
|
if (e.Code != this.code) return false; |
||||||
|
var v = e.Operand as ILVariable; |
||||||
|
return v != null && (this.b ? Capture(ref pm.B, v) : Capture(ref pm.A, v)); |
||||||
|
} |
||||||
|
|
||||||
|
static bool Capture(ref ILVariable pmvar, ILVariable v) |
||||||
|
{ |
||||||
|
if (pmvar != null) return pmvar == v; |
||||||
|
pmvar = v; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
static readonly ILExpression[] EmptyArguments = new ILExpression[0]; |
||||||
|
public override ILExpression BuildNew(PatternMatcher pm) |
||||||
|
{ |
||||||
|
var v = this.b ? pm.B : pm.A; |
||||||
|
var e = new ILExpression(ILCode.Ldloc, v, EmptyArguments); |
||||||
|
if (TypeAnalysis.IsNullableType(v.Type)) e = new ILExpression(ILCode.ValueOf, null, e); |
||||||
|
return e; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sealed class BooleanPattern : Pattern |
||||||
|
{ |
||||||
|
public static readonly Pattern False = new BooleanPattern(false), True = new BooleanPattern(true); |
||||||
|
|
||||||
|
readonly object value; |
||||||
|
BooleanPattern(bool value) |
||||||
|
: base(null) |
||||||
|
{ |
||||||
|
this.value = Convert.ToInt32(value); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool Match(PatternMatcher pm, ILExpression e) |
||||||
|
{ |
||||||
|
return e.Code == ILCode.Ldc_I4 && TypeAnalysis.IsBoolean(e.InferredType) && object.Equals(e.Operand, value); |
||||||
|
} |
||||||
|
|
||||||
|
public override ILExpression BuildNew(PatternMatcher pm) |
||||||
|
{ |
||||||
|
// boolean constants are wrapped inside a container to disable simplyfication of equality comparisons
|
||||||
|
return new ILExpression(ILCode.Wrap, null, new ILExpression(ILCode.Ldc_I4, value)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static readonly Pattern VariableRefA = new VariablePattern(ILCode.Ldloca, false), VariableRefB = new VariablePattern(ILCode.Ldloca, true); |
||||||
|
static readonly Pattern VariableA = new VariablePattern(ILCode.Ldloc, false), VariableB = new VariablePattern(ILCode.Ldloc, true); |
||||||
|
static readonly Pattern VariableAHasValue = new MethodPattern(ILCode.CallGetter, "get_HasValue", VariableRefA); |
||||||
|
static readonly Pattern VariableAGetValueOrDefault = new MethodPattern(ILCode.Call, "GetValueOrDefault", VariableRefA); |
||||||
|
static readonly Pattern VariableBHasValue = new MethodPattern(ILCode.CallGetter, "get_HasValue", VariableRefB); |
||||||
|
static readonly Pattern VariableBGetValueOrDefault = new MethodPattern(ILCode.Call, "GetValueOrDefault", VariableRefB); |
||||||
|
static readonly Pattern CeqHasValue = new ILPattern(ILCode.Ceq, VariableAHasValue, VariableBHasValue); |
||||||
|
static readonly Pattern CneHasValue = new ILPattern(ILCode.Cne, VariableAHasValue, VariableBHasValue); |
||||||
|
static readonly Pattern AndHasValue = new ILPattern(ILCode.And, VariableAHasValue, VariableBHasValue); |
||||||
|
static readonly Pattern Any = new AnyPattern(); |
||||||
|
static readonly Pattern OperatorVariableAB = new OperatorPattern(); |
||||||
|
|
||||||
|
static OperatorPattern OperatorNN(OperatorType type) |
||||||
|
{ |
||||||
|
return new OperatorPattern(type, false); |
||||||
|
} |
||||||
|
|
||||||
|
static OperatorPattern OperatorNV(OperatorType type) |
||||||
|
{ |
||||||
|
return new OperatorPattern(type, true); |
||||||
|
} |
||||||
|
|
||||||
|
static Pattern NewObj(Pattern p) |
||||||
|
{ |
||||||
|
return new MethodPattern(ILCode.Newobj, ".ctor", p); |
||||||
|
} |
||||||
|
|
||||||
|
static readonly Pattern[] Comparisons = new Pattern[] { |
||||||
|
/* both operands nullable */ |
||||||
|
// == (primitive, decimal)
|
||||||
|
OperatorNN(OperatorType.Equality) & CeqHasValue, |
||||||
|
// == (struct)
|
||||||
|
CeqHasValue & (!VariableAHasValue | OperatorNN(OperatorType.Equality)), |
||||||
|
// != (primitive, decimal)
|
||||||
|
OperatorNN(OperatorType.InEquality) | CneHasValue, |
||||||
|
// != (struct)
|
||||||
|
CneHasValue | (VariableAHasValue & OperatorNN(OperatorType.InEquality)), |
||||||
|
// > , < , >= , <= (primitive, decimal)
|
||||||
|
OperatorNN(OperatorType.Comparison) & AndHasValue, |
||||||
|
// > , < , >= , <= (struct)
|
||||||
|
AndHasValue & OperatorNN(OperatorType.Comparison), |
||||||
|
|
||||||
|
/* only one operand nullable */ |
||||||
|
// == (primitive, decimal)
|
||||||
|
OperatorNV(OperatorType.Equality) & VariableAHasValue, |
||||||
|
// == (struct)
|
||||||
|
VariableAHasValue & OperatorNV(OperatorType.Equality), |
||||||
|
// != (primitive, decimal)
|
||||||
|
OperatorNV(OperatorType.InEquality) | !VariableAHasValue, |
||||||
|
// != (struct)
|
||||||
|
!VariableAHasValue | OperatorNV(OperatorType.InEquality), |
||||||
|
// > , <, >= , <= (primitive, decimal)
|
||||||
|
OperatorNV(OperatorType.Comparison) & VariableAHasValue, |
||||||
|
// > , < , >= , <= (struct)
|
||||||
|
VariableAHasValue & OperatorNV(OperatorType.Comparison), |
||||||
|
}; |
||||||
|
|
||||||
|
static readonly Pattern[] Other = new Pattern[] { |
||||||
|
/* both operands nullable */ |
||||||
|
// & (bool)
|
||||||
|
new ILPattern(ILCode.TernaryOp, VariableAGetValueOrDefault | (!VariableBGetValueOrDefault & !VariableAHasValue), VariableB, VariableA), |
||||||
|
new ILPattern(ILCode.And, VariableA, VariableB), |
||||||
|
// | (bool)
|
||||||
|
new ILPattern(ILCode.TernaryOp, VariableAGetValueOrDefault | (!VariableBGetValueOrDefault & !VariableAHasValue), VariableA, VariableB), |
||||||
|
new ILPattern(ILCode.Or, VariableA, VariableB), |
||||||
|
// null coalescing
|
||||||
|
new ILPattern(ILCode.TernaryOp, VariableAHasValue, NewObj(VariableAGetValueOrDefault), VariableB), |
||||||
|
new ILPattern(ILCode.NullCoalescing, VariableA, VariableB), |
||||||
|
// all other
|
||||||
|
new ILPattern(ILCode.TernaryOp, AndHasValue, NewObj(OperatorNN(OperatorType.Other)), new ILPattern(ILCode.DefaultValue)), |
||||||
|
OperatorVariableAB, |
||||||
|
|
||||||
|
/* only one operand nullable */ |
||||||
|
// & (bool)
|
||||||
|
new ILPattern(ILCode.TernaryOp, Any, VariableA, NewObj(BooleanPattern.False)), |
||||||
|
new ILPattern(ILCode.And, VariableA, Any), |
||||||
|
// | (bool)
|
||||||
|
new ILPattern(ILCode.TernaryOp, Any, NewObj(BooleanPattern.True), VariableA), |
||||||
|
new ILPattern(ILCode.Or, VariableA, Any), |
||||||
|
// == true
|
||||||
|
VariableAGetValueOrDefault & VariableAHasValue, |
||||||
|
new ILPattern(ILCode.Ceq, VariableA, BooleanPattern.True), |
||||||
|
// != true
|
||||||
|
!VariableAGetValueOrDefault | !VariableAHasValue, |
||||||
|
new ILPattern(ILCode.Cne, VariableA, BooleanPattern.True), |
||||||
|
// == false
|
||||||
|
!VariableAGetValueOrDefault & VariableAHasValue, |
||||||
|
new ILPattern(ILCode.Ceq, VariableA, BooleanPattern.False), |
||||||
|
// != false
|
||||||
|
VariableAGetValueOrDefault | !VariableAHasValue, |
||||||
|
new ILPattern(ILCode.Cne, VariableA, BooleanPattern.False), |
||||||
|
// ?? true
|
||||||
|
!VariableAHasValue | VariableAGetValueOrDefault, |
||||||
|
new ILPattern(ILCode.NullCoalescing, VariableA, BooleanPattern.True), |
||||||
|
// ?? false
|
||||||
|
VariableAHasValue & VariableAGetValueOrDefault, |
||||||
|
new ILPattern(ILCode.NullCoalescing, VariableA, BooleanPattern.False), |
||||||
|
// null coalescing
|
||||||
|
new ILPattern(ILCode.TernaryOp, VariableAHasValue, VariableAGetValueOrDefault, Any), |
||||||
|
new ILPattern(ILCode.NullCoalescing, VariableA, Any), |
||||||
|
// all other
|
||||||
|
new ILPattern(ILCode.TernaryOp, VariableAHasValue, NewObj(OperatorNV(OperatorType.Other)), new ILPattern(ILCode.DefaultValue)), |
||||||
|
OperatorVariableAB, |
||||||
|
}; |
||||||
|
|
||||||
|
ILVariable A, B; |
||||||
|
ILExpression Operator, SimpleOperand; |
||||||
|
bool SimpleLeftOperand; |
||||||
|
|
||||||
|
void Reset() |
||||||
|
{ |
||||||
|
this.A = null; |
||||||
|
this.B = null; |
||||||
|
this.Operator = null; |
||||||
|
this.SimpleOperand = null; |
||||||
|
this.SimpleLeftOperand = false; |
||||||
|
} |
||||||
|
|
||||||
|
bool Simplify(ILExpression expr) |
||||||
|
{ |
||||||
|
if (expr.Code == ILCode.TernaryOp || expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr) { |
||||||
|
Pattern[] ps; |
||||||
|
if (expr.Code != ILCode.TernaryOp) { |
||||||
|
ps = Comparisons; |
||||||
|
for (int i = 0; i < ps.Length; i++) { |
||||||
|
this.Reset(); |
||||||
|
if (!ps[i].Match(this, expr)) continue; |
||||||
|
SetResult(expr, OperatorVariableAB.BuildNew(this)); |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
ps = Other; |
||||||
|
for (int i = 0; i < ps.Length; i += 2) { |
||||||
|
this.Reset(); |
||||||
|
if (!ps[i].Match(this, expr)) continue; |
||||||
|
var n = ps[i + 1].BuildNew(this); |
||||||
|
SetResult(expr, n); |
||||||
|
if (n.Code == ILCode.NullCoalescing) { |
||||||
|
// if both operands are nullable then the result is also nullable
|
||||||
|
if (n.Arguments[1].Code == ILCode.ValueOf) { |
||||||
|
n.Arguments[0] = n.Arguments[0].Arguments[0]; |
||||||
|
n.Arguments[1] = n.Arguments[1].Arguments[0]; |
||||||
|
} |
||||||
|
} else if (n.Code != ILCode.Ceq && n.Code != ILCode.Cne) { |
||||||
|
expr.Code = ILCode.NullableOf; |
||||||
|
expr.InferredType = expr.ExpectedType = null; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
static void SetResult(ILExpression expr, ILExpression n) |
||||||
|
{ |
||||||
|
// IL ranges from removed nodes are assigned to the new operator expression
|
||||||
|
var removednodes = expr.GetSelfAndChildrenRecursive<ILExpression>().Except(n.GetSelfAndChildrenRecursive<ILExpression>()); |
||||||
|
n.ILRanges = ILRange.OrderAndJoint(n.ILRanges.Concat(removednodes.SelectMany(el => el.ILRanges))); |
||||||
|
// the new expression is wrapped in a container so that negations aren't pushed through lifted comparison operations
|
||||||
|
expr.Code = ILCode.Wrap; |
||||||
|
expr.Arguments.Clear(); |
||||||
|
expr.Arguments.Add(n); |
||||||
|
expr.ILRanges.Clear(); |
||||||
|
expr.InferredType = n.InferredType; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,27 +0,0 @@ |
|||||||
#region Using directives
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Resources; |
|
||||||
using System.Reflection; |
|
||||||
using System.Runtime.InteropServices; |
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
[assembly: AssemblyTitle("ICSharpCode.Decompiler")] |
|
||||||
[assembly: AssemblyDescription("IL decompiler engine")] |
|
||||||
[assembly: AssemblyCompany("ic#code")] |
|
||||||
[assembly: AssemblyProduct("ILSpy")] |
|
||||||
[assembly: AssemblyCopyright("Copyright 2011 AlphaSierraPapa for the SharpDevelop Team")] |
|
||||||
[assembly: AssemblyTrademark("")] |
|
||||||
[assembly: AssemblyCulture("")] |
|
||||||
|
|
||||||
// This sets the default COM visibility of types in the assembly to invisible.
|
|
||||||
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
|
|
||||||
[assembly: ComVisible(false)] |
|
||||||
|
|
||||||
[assembly: AssemblyVersion("$INSERTVERSION$")] |
|
||||||
[assembly: AssemblyInformationalVersion("$INSERTVERSION$$INSERTBRANCHPOSTFIX$$INSERTVERSIONNAMEPOSTFIX$-$INSERTSHORTCOMMITHASH$")] |
|
||||||
[assembly: NeutralResourcesLanguage("en-US")] |
|
||||||
|
|
||||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly", |
|
||||||
Justification = "AssemblyInformationalVersion does not need to be a parsable version")] |
|
@ -0,0 +1,370 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Linq.Expressions; |
||||||
|
using System.Xml; |
||||||
|
|
||||||
|
public class ExpressionTrees |
||||||
|
{ |
||||||
|
class GenericClass<X> |
||||||
|
{ |
||||||
|
public static X StaticField; |
||||||
|
public X InstanceField; |
||||||
|
public static X StaticProperty { get; set; } |
||||||
|
public X InstanceProperty { get; set; } |
||||||
|
|
||||||
|
public static bool GenericMethod<Y>() |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int field; |
||||||
|
|
||||||
|
static object ToCode<R>(object x, Expression<Func<R>> expr) |
||||||
|
{ |
||||||
|
return expr; |
||||||
|
} |
||||||
|
|
||||||
|
static object ToCode<T, R>(object x, Expression<Func<T, R>> expr) |
||||||
|
{ |
||||||
|
return expr; |
||||||
|
} |
||||||
|
|
||||||
|
static object X() |
||||||
|
{ |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public void Parameter(bool a) |
||||||
|
{ |
||||||
|
ToCode(X(), () => a); |
||||||
|
} |
||||||
|
|
||||||
|
public void LocalVariable() |
||||||
|
{ |
||||||
|
bool a = true; |
||||||
|
ToCode(X(), () => a); |
||||||
|
} |
||||||
|
|
||||||
|
public void LambdaParameter() |
||||||
|
{ |
||||||
|
ToCode(X(), (bool a) => a); |
||||||
|
} |
||||||
|
|
||||||
|
public void AddOperator(int x) |
||||||
|
{ |
||||||
|
ToCode(X(), () => 1 + x + 2); |
||||||
|
} |
||||||
|
|
||||||
|
public void AnonymousClasses() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new { X = 3, A = "a" }); |
||||||
|
} |
||||||
|
|
||||||
|
public void ArrayIndex() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new[] { 3, 4, 5 }[0 + (int)(DateTime.Now.Ticks % 3)]); |
||||||
|
} |
||||||
|
|
||||||
|
public void ArrayLengthAndDoubles() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new[] { 1.0, 2.01, 3.5 }.Concat(new[] { 1.0, 2.0 }).ToArray().Length); |
||||||
|
} |
||||||
|
|
||||||
|
public void AsOperator() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new object() as string); |
||||||
|
} |
||||||
|
|
||||||
|
public void ComplexGenericName() |
||||||
|
{ |
||||||
|
ToCode(X(), () => ((Func<int, bool>)(x => x > 0))(0)); |
||||||
|
} |
||||||
|
|
||||||
|
public void DefaultValue() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new TimeSpan(1, 2, 3) == default(TimeSpan)); |
||||||
|
} |
||||||
|
|
||||||
|
public void EnumConstant() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new object().Equals(MidpointRounding.ToEven)); |
||||||
|
} |
||||||
|
|
||||||
|
public void IndexerAccess() |
||||||
|
{ |
||||||
|
var dict = Enumerable.Range(1, 20).ToDictionary(n => n.ToString()); |
||||||
|
ToCode(X(), () => dict["3"] == 3); |
||||||
|
} |
||||||
|
|
||||||
|
public void IsOperator() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new object() is string); |
||||||
|
} |
||||||
|
|
||||||
|
public void ListInitializer() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new Dictionary<int, int> { { 1, 1 }, { 2, 2 }, { 3, 4 } }.Count == 3); |
||||||
|
} |
||||||
|
|
||||||
|
public void ListInitializer2() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new List<int>(50) { 1, 2, 3 }.Count == 3); |
||||||
|
} |
||||||
|
|
||||||
|
public void ListInitializer3() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new List<int> { 1, 2, 3 }.Count == 3); |
||||||
|
} |
||||||
|
|
||||||
|
public void LiteralCharAndProperty() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new string(' ', 3).Length == 1); |
||||||
|
} |
||||||
|
|
||||||
|
public void CharNoCast() |
||||||
|
{ |
||||||
|
ToCode(X(), () => "abc"[1] == 'b'); |
||||||
|
} |
||||||
|
|
||||||
|
public void StringsImplicitCast() |
||||||
|
{ |
||||||
|
int i = 1; |
||||||
|
string x = "X"; |
||||||
|
ToCode(X(), () => (("a\n\\b" ?? x) + x).Length == 2 ? false : true && (1m + -i > 0 || false)); |
||||||
|
} |
||||||
|
|
||||||
|
public void NotImplicitCast() |
||||||
|
{ |
||||||
|
byte z = 42; |
||||||
|
ToCode(X(), () => ~z == 0); |
||||||
|
} |
||||||
|
|
||||||
|
public void MembersBuiltin() |
||||||
|
{ |
||||||
|
ToCode(X(), () => 1.23m.ToString()); |
||||||
|
ToCode(X(), () => AttributeTargets.All.HasFlag((Enum)AttributeTargets.Assembly)); |
||||||
|
ToCode(X(), () => "abc".Length == 3); |
||||||
|
ToCode(X(), () => 'a'.CompareTo('b') < 0); |
||||||
|
} |
||||||
|
|
||||||
|
public void MembersDefault() |
||||||
|
{ |
||||||
|
ToCode(X(), () => default(DateTime).Ticks == 0); |
||||||
|
ToCode(X(), () => default(int[]).Length == 0); |
||||||
|
ToCode(X(), () => default(Type).IsLayoutSequential); |
||||||
|
ToCode(X(), () => default(List<int>).Count); |
||||||
|
ToCode(X(), () => default(int[]).Clone() == null); |
||||||
|
ToCode(X(), () => default(Type).IsInstanceOfType(new object())); |
||||||
|
ToCode(X(), () => default(List<int>).AsReadOnly()); |
||||||
|
} |
||||||
|
|
||||||
|
public void DoAssert() |
||||||
|
{ |
||||||
|
field = 37; |
||||||
|
ToCode(X(), () => field != C()); |
||||||
|
ToCode(X(), () => !ReferenceEquals(this, new ExpressionTrees())); |
||||||
|
ToCode(X(), () => MyEquals(this) && !MyEquals(default(ExpressionTrees))); |
||||||
|
} |
||||||
|
|
||||||
|
int C() |
||||||
|
{ |
||||||
|
return field + 5; |
||||||
|
} |
||||||
|
|
||||||
|
bool MyEquals(ExpressionTrees other) |
||||||
|
{ |
||||||
|
return other != null && field == other.field; |
||||||
|
} |
||||||
|
|
||||||
|
public void MethodGroupAsExtensionMethod() |
||||||
|
{ |
||||||
|
ToCode(X(), () => (Func<bool>)new[] { 2000, 2004, 2008, 2012 }.Any); |
||||||
|
} |
||||||
|
|
||||||
|
public void MethodGroupConstant() |
||||||
|
{ |
||||||
|
ToCode(X(), () => Array.TrueForAll(new[] { 2000, 2004, 2008, 2012 }, DateTime.IsLeapYear)); |
||||||
|
|
||||||
|
HashSet<int> set = new HashSet<int>(); |
||||||
|
ToCode(X(), () => new[] { 2000, 2004, 2008, 2012 }.All(set.Add)); |
||||||
|
|
||||||
|
Func<Func<object, object, bool>, bool> sink = f => f(null, null); |
||||||
|
ToCode(X(), () => sink(int.Equals)); |
||||||
|
} |
||||||
|
|
||||||
|
public void MultipleCasts() |
||||||
|
{ |
||||||
|
ToCode(X(), () => 1 == (int)(object)1); |
||||||
|
} |
||||||
|
|
||||||
|
public void MultipleDots() |
||||||
|
{ |
||||||
|
ToCode(X(), () => 3.ToString().ToString().Length > 0); |
||||||
|
} |
||||||
|
|
||||||
|
public void NestedLambda() |
||||||
|
{ |
||||||
|
Func<Func<int>, int> call = f => f(); |
||||||
|
//no params
|
||||||
|
ToCode(X(), () => call(() => 42)); |
||||||
|
//one param
|
||||||
|
ToCode(X(), () => new[] { 37, 42 }.Select(x => x * 2)); |
||||||
|
//two params
|
||||||
|
ToCode(X(), () => new[] { 37, 42 }.Select((x, i) => x * 2)); |
||||||
|
} |
||||||
|
|
||||||
|
public void CurriedLambda() |
||||||
|
{ |
||||||
|
ToCode<int, Func<int, Func<int, int>>>(X(), a => b => c => a + b + c); |
||||||
|
} |
||||||
|
|
||||||
|
bool Fizz(Func<int, bool> a) |
||||||
|
{ |
||||||
|
return a(42); |
||||||
|
} |
||||||
|
|
||||||
|
bool Buzz(Func<int, bool> a) |
||||||
|
{ |
||||||
|
return a(42); |
||||||
|
} |
||||||
|
|
||||||
|
bool Fizz(Func<string, bool> a) |
||||||
|
{ |
||||||
|
return a("42"); |
||||||
|
} |
||||||
|
|
||||||
|
public void NestedLambda2() |
||||||
|
{ |
||||||
|
ToCode(X(), () => Fizz(x => x == "a")); |
||||||
|
ToCode(X(), () => Fizz(x => x == 37)); |
||||||
|
|
||||||
|
ToCode(X(), () => Fizz((int x) => true)); |
||||||
|
ToCode(X(), () => Buzz(x => true)); |
||||||
|
} |
||||||
|
|
||||||
|
public void NewArrayAndExtensionMethod() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new[] { 1.0, 2.01, 3.5 }.SequenceEqual(new[] { 1.0, 2.01, 3.5 })); |
||||||
|
} |
||||||
|
|
||||||
|
public void NewMultiDimArray() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new int[3, 4].Length == 1); |
||||||
|
} |
||||||
|
|
||||||
|
public void NewObject() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new object() != new object()); |
||||||
|
} |
||||||
|
|
||||||
|
public void NotOperator() |
||||||
|
{ |
||||||
|
bool x = true; |
||||||
|
int y = 3; |
||||||
|
byte z = 42; |
||||||
|
ToCode(X(), () => ~(int)z == 0); |
||||||
|
ToCode(X(), () => ~y == 0); |
||||||
|
ToCode(X(), () => !x); |
||||||
|
} |
||||||
|
|
||||||
|
public void ObjectInitializers() |
||||||
|
{ |
||||||
|
XmlReaderSettings s = new XmlReaderSettings { |
||||||
|
CloseInput = false, |
||||||
|
CheckCharacters = false |
||||||
|
}; |
||||||
|
ToCode(X(), () => new XmlReaderSettings { CloseInput = s.CloseInput, CheckCharacters = s.CheckCharacters }.Equals(s)); |
||||||
|
} |
||||||
|
|
||||||
|
public void Quoted() |
||||||
|
{ |
||||||
|
ToCode(X(), () => (Expression<Func<int, string, string>>)((n, s) => s + n.ToString()) != null); |
||||||
|
} |
||||||
|
|
||||||
|
public void Quoted2() |
||||||
|
{ |
||||||
|
ToCode(X(), () => ToCode(X(), () => true).Equals(null)); |
||||||
|
} |
||||||
|
|
||||||
|
public void QuotedWithAnonymous() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new[] { new { X = "a", Y = "b" } }.Select(o => o.X + o.Y).Single()); |
||||||
|
} |
||||||
|
|
||||||
|
public void StaticCall() |
||||||
|
{ |
||||||
|
ToCode(X(), () => Equals(3, 0)); |
||||||
|
} |
||||||
|
|
||||||
|
public void ThisCall() |
||||||
|
{ |
||||||
|
ToCode(X(), () => !Equals(3)); |
||||||
|
} |
||||||
|
|
||||||
|
public void ThisExplicit() |
||||||
|
{ |
||||||
|
ToCode(X(), () => object.Equals(this, 3)); |
||||||
|
} |
||||||
|
|
||||||
|
public void TypedConstant() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new[] { typeof(int), typeof(string) }); |
||||||
|
} |
||||||
|
|
||||||
|
public void StaticCallImplicitCast() |
||||||
|
{ |
||||||
|
ToCode(X(), () => Equals(3, 0)); |
||||||
|
} |
||||||
|
|
||||||
|
public void StaticMembers() |
||||||
|
{ |
||||||
|
ToCode(X(), () => (DateTime.Now > DateTime.Now + TimeSpan.FromMilliseconds(10.001)).ToString() == "False"); |
||||||
|
} |
||||||
|
|
||||||
|
public void Strings() |
||||||
|
{ |
||||||
|
int i = 1; |
||||||
|
string x = "X"; |
||||||
|
ToCode(X(), () => (("a\n\\b" ?? x) + x).Length == 2 ? false : true && (1m + (decimal)-i > 0m || false)); |
||||||
|
} |
||||||
|
|
||||||
|
public void StringAccessor() |
||||||
|
{ |
||||||
|
ToCode(X(), () => (int)"abc"[1] == 98); |
||||||
|
} |
||||||
|
|
||||||
|
public void GenericClassInstance() |
||||||
|
{ |
||||||
|
ToCode(X(), () => new GenericClass<int>().InstanceField + new GenericClass<double>().InstanceProperty); |
||||||
|
} |
||||||
|
|
||||||
|
public void GenericClassStatic() |
||||||
|
{ |
||||||
|
ToCode(X(), () => GenericClass<int>.StaticField + GenericClass<double>.StaticProperty); |
||||||
|
} |
||||||
|
|
||||||
|
public void InvokeGenericMethod() |
||||||
|
{ |
||||||
|
ToCode(X(), () => GenericClass<int>.GenericMethod<double>()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,830 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Runtime.InteropServices; |
||||||
|
|
||||||
|
public static class LiftedOperators |
||||||
|
{ |
||||||
|
// C# uses 4 different patterns of IL for lifted operators: bool, other primitive types, decimal, other structs.
|
||||||
|
// Different patterns are used depending on whether both of the operands are nullable or only the left/right operand is nullable.
|
||||||
|
// Negation must not be pushed through such comparisons because it would change the semantics.
|
||||||
|
// A comparison used in a condition differs somewhat from a comparison used as a simple value.
|
||||||
|
|
||||||
|
public static void BoolBasic(bool? a, bool? b) |
||||||
|
{ |
||||||
|
if (a == b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(a == b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(a != b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void BoolComplex(bool? a, Func<bool> x) |
||||||
|
{ |
||||||
|
if (a == x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (x() == a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (x() != a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(a == x())) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(a != x())) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(x() == a)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(x() != a)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void BoolConst(bool? a) |
||||||
|
{ |
||||||
|
if (a == true) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != true) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a == false) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != false) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a ?? true) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a ?? false) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void BoolValueBasic(bool? a, bool? b) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == b); |
||||||
|
Console.WriteLine(a != b); |
||||||
|
|
||||||
|
Console.WriteLine(!(a == b)); |
||||||
|
Console.WriteLine(!(a != b)); |
||||||
|
|
||||||
|
Console.WriteLine(a & b); |
||||||
|
Console.WriteLine(a | b); |
||||||
|
Console.WriteLine(a ^ b); |
||||||
|
Console.WriteLine(a ?? b); |
||||||
|
Console.WriteLine(!a); |
||||||
|
a &= b; |
||||||
|
a |= b; |
||||||
|
a ^= b; |
||||||
|
} |
||||||
|
|
||||||
|
public static void BoolValueComplex(bool? a, Func<bool> x) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == x()); |
||||||
|
Console.WriteLine(a != x()); |
||||||
|
|
||||||
|
Console.WriteLine(x() == a); |
||||||
|
Console.WriteLine(x() != a); |
||||||
|
|
||||||
|
Console.WriteLine(!(a == x())); |
||||||
|
Console.WriteLine(!(a != x())); |
||||||
|
|
||||||
|
Console.WriteLine(a & x()); |
||||||
|
Console.WriteLine(a | x()); |
||||||
|
Console.WriteLine(a ^ x()); |
||||||
|
Console.WriteLine(a ?? x()); |
||||||
|
a &= x(); |
||||||
|
a |= x(); |
||||||
|
a ^= x(); |
||||||
|
|
||||||
|
Console.WriteLine(x() ^ a); |
||||||
|
(new bool?[0])[0] ^= x(); |
||||||
|
} |
||||||
|
|
||||||
|
public static void BoolValueConst(bool? a) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == true); |
||||||
|
Console.WriteLine(a != true); |
||||||
|
Console.WriteLine(a == false); |
||||||
|
Console.WriteLine(a != false); |
||||||
|
Console.WriteLine(a ?? true); |
||||||
|
Console.WriteLine(a ?? false); |
||||||
|
} |
||||||
|
|
||||||
|
public static void IntBasic(int? a, int? b) |
||||||
|
{ |
||||||
|
if (a == b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a > b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a < b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a >= b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a <= b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(a == b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(a != b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(a > b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void IntComplex(int? a, Func<int> x) |
||||||
|
{ |
||||||
|
if (a == x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a > x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (x() == a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (x() != a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (x() > a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(a == x())) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(a != x())) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(a > x())) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void IntConst(int? a) |
||||||
|
{ |
||||||
|
if (a == 2) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != 2) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a > 2) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (2 == a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (2 != a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (2 > a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void IntValueBasic(int? a, int? b) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == b); |
||||||
|
Console.WriteLine(a != b); |
||||||
|
Console.WriteLine(a > b); |
||||||
|
|
||||||
|
Console.WriteLine(!(a == b)); |
||||||
|
Console.WriteLine(!(a != b)); |
||||||
|
Console.WriteLine(!(a > b)); |
||||||
|
|
||||||
|
Console.WriteLine(a + b); |
||||||
|
Console.WriteLine(a - b); |
||||||
|
Console.WriteLine(a * b); |
||||||
|
Console.WriteLine(a / b); |
||||||
|
Console.WriteLine(a % b); |
||||||
|
Console.WriteLine(a & b); |
||||||
|
Console.WriteLine(a | b); |
||||||
|
Console.WriteLine(a ^ b); |
||||||
|
Console.WriteLine(a << b); |
||||||
|
Console.WriteLine(a >> b); |
||||||
|
Console.WriteLine(a ?? b); |
||||||
|
Console.WriteLine(-a); |
||||||
|
Console.WriteLine(~a); |
||||||
|
// TODO:
|
||||||
|
//Console.WriteLine(a++);
|
||||||
|
//Console.WriteLine(a--);
|
||||||
|
Console.WriteLine(++a); |
||||||
|
Console.WriteLine(--a); |
||||||
|
a += b; |
||||||
|
a -= b; |
||||||
|
a *= b; |
||||||
|
a /= b; |
||||||
|
a %= b; |
||||||
|
a &= b; |
||||||
|
a |= b; |
||||||
|
a ^= b; |
||||||
|
a <<= b; |
||||||
|
a >>= b; |
||||||
|
} |
||||||
|
|
||||||
|
public static void IntValueComplex(int? a, Func<int> x) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == x()); |
||||||
|
Console.WriteLine(a != x()); |
||||||
|
Console.WriteLine(a > x()); |
||||||
|
|
||||||
|
Console.WriteLine(x() == a); |
||||||
|
Console.WriteLine(x() != a); |
||||||
|
Console.WriteLine(x() > a); |
||||||
|
|
||||||
|
Console.WriteLine(a + x()); |
||||||
|
Console.WriteLine(a - x()); |
||||||
|
Console.WriteLine(a * x()); |
||||||
|
Console.WriteLine(a / x()); |
||||||
|
Console.WriteLine(a % x()); |
||||||
|
Console.WriteLine(a & x()); |
||||||
|
Console.WriteLine(a | x()); |
||||||
|
Console.WriteLine(a ^ x()); |
||||||
|
Console.WriteLine(a << x()); |
||||||
|
Console.WriteLine(a >> x()); |
||||||
|
Console.WriteLine(a ?? x()); |
||||||
|
a += x(); |
||||||
|
a -= x(); |
||||||
|
a *= x(); |
||||||
|
a /= x(); |
||||||
|
a %= x(); |
||||||
|
a &= x(); |
||||||
|
a |= x(); |
||||||
|
a ^= x(); |
||||||
|
a <<= x(); |
||||||
|
a >>= x(); |
||||||
|
|
||||||
|
Console.WriteLine(x() + a); |
||||||
|
(new int?[0])[0] += x(); |
||||||
|
} |
||||||
|
|
||||||
|
public static void IntValueConst(int? a) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == 2); |
||||||
|
Console.WriteLine(a != 2); |
||||||
|
Console.WriteLine(a > 2); |
||||||
|
|
||||||
|
Console.WriteLine(2 == a); |
||||||
|
Console.WriteLine(2 != a); |
||||||
|
Console.WriteLine(2 > a); |
||||||
|
|
||||||
|
Console.WriteLine(a + 2); |
||||||
|
Console.WriteLine(a - 2); |
||||||
|
Console.WriteLine(a * 2); |
||||||
|
Console.WriteLine(a / 2); |
||||||
|
Console.WriteLine(a % 2); |
||||||
|
Console.WriteLine(a & 2); |
||||||
|
Console.WriteLine(a | 2); |
||||||
|
Console.WriteLine(a ^ 2); |
||||||
|
Console.WriteLine(a << 2); |
||||||
|
Console.WriteLine(a >> 2); |
||||||
|
Console.WriteLine(a ?? 2); |
||||||
|
a += 2; |
||||||
|
a -= 2; |
||||||
|
a *= 2; |
||||||
|
a /= 2; |
||||||
|
a %= 2; |
||||||
|
a &= 2; |
||||||
|
a |= 2; |
||||||
|
a ^= 2; |
||||||
|
a <<= 2; |
||||||
|
a >>= 2; |
||||||
|
|
||||||
|
Console.WriteLine(2 + a); |
||||||
|
} |
||||||
|
|
||||||
|
public static void NumberBasic(decimal? a, decimal? b) |
||||||
|
{ |
||||||
|
if (a == b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a > b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a < b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a >= b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a <= b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(a == b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(a != b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(a > b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void NumberComplex(decimal? a, Func<decimal> x) |
||||||
|
{ |
||||||
|
if (a == x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a > x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (x() == a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (x() != a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (x() > a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void NumberConst(decimal? a) |
||||||
|
{ |
||||||
|
if (a == 2m) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != 2m) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a > 2m) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (2m == a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (2m != a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (2m > a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void NumberValueBasic(decimal? a, decimal? b) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == b); |
||||||
|
Console.WriteLine(a != b); |
||||||
|
Console.WriteLine(a > b); |
||||||
|
|
||||||
|
Console.WriteLine(!(a == b)); |
||||||
|
Console.WriteLine(!(a != b)); |
||||||
|
Console.WriteLine(!(a > b)); |
||||||
|
|
||||||
|
Console.WriteLine(a + b); |
||||||
|
Console.WriteLine(a - b); |
||||||
|
Console.WriteLine(a * b); |
||||||
|
Console.WriteLine(a / b); |
||||||
|
Console.WriteLine(a % b); |
||||||
|
Console.WriteLine(a ?? b); |
||||||
|
Console.WriteLine(-a); |
||||||
|
// TODO:
|
||||||
|
//Console.WriteLine(a++);
|
||||||
|
//Console.WriteLine(a--);
|
||||||
|
//Console.WriteLine(++a);
|
||||||
|
//Console.WriteLine(--a);
|
||||||
|
a += b; |
||||||
|
a -= b; |
||||||
|
a *= b; |
||||||
|
a /= b; |
||||||
|
a %= b; |
||||||
|
} |
||||||
|
|
||||||
|
public static void NumberValueComplex(decimal? a, Func<decimal> x) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == x()); |
||||||
|
Console.WriteLine(a != x()); |
||||||
|
Console.WriteLine(a > x()); |
||||||
|
|
||||||
|
Console.WriteLine(x() == a); |
||||||
|
Console.WriteLine(x() != a); |
||||||
|
Console.WriteLine(x() > a); |
||||||
|
|
||||||
|
Console.WriteLine(a + x()); |
||||||
|
Console.WriteLine(a - x()); |
||||||
|
Console.WriteLine(a * x()); |
||||||
|
Console.WriteLine(a / x()); |
||||||
|
Console.WriteLine(a % x()); |
||||||
|
Console.WriteLine(a ?? x()); |
||||||
|
a += x(); |
||||||
|
a -= x(); |
||||||
|
a *= x(); |
||||||
|
a /= x(); |
||||||
|
a %= x(); |
||||||
|
|
||||||
|
Console.WriteLine(x() + a); |
||||||
|
(new decimal?[0])[0] += x(); |
||||||
|
} |
||||||
|
|
||||||
|
public static void NumberValueConst(decimal? a) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == 2m); |
||||||
|
Console.WriteLine(a != 2m); |
||||||
|
Console.WriteLine(a > 2m); |
||||||
|
|
||||||
|
Console.WriteLine(2m == a); |
||||||
|
Console.WriteLine(2m != a); |
||||||
|
Console.WriteLine(2m > a); |
||||||
|
|
||||||
|
Console.WriteLine(a + 2m); |
||||||
|
Console.WriteLine(a - 2m); |
||||||
|
Console.WriteLine(a * 2m); |
||||||
|
Console.WriteLine(a / 2m); |
||||||
|
Console.WriteLine(a % 2m); |
||||||
|
Console.WriteLine(a ?? 2m); |
||||||
|
a += 2m; |
||||||
|
a -= 2m; |
||||||
|
a *= 2m; |
||||||
|
a /= 2m; |
||||||
|
a %= 2m; |
||||||
|
|
||||||
|
Console.WriteLine(2m + a); |
||||||
|
} |
||||||
|
|
||||||
|
public static void StructBasic(TS? a, TS? b) |
||||||
|
{ |
||||||
|
if (a == b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a > b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a < b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a >= b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a <= b) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(a == b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(a != b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (!(a > b)) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void StructComplex(TS? a, Func<TS> x) |
||||||
|
{ |
||||||
|
if (a == x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a != x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (a > x()) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
|
||||||
|
if (x() == a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (x() != a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
if (x() > a) |
||||||
|
{ |
||||||
|
Console.WriteLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void StructValueBasic(TS? a, TS? b, int? i) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == b); |
||||||
|
Console.WriteLine(a != b); |
||||||
|
Console.WriteLine(a > b); |
||||||
|
|
||||||
|
Console.WriteLine(!(a == b)); |
||||||
|
Console.WriteLine(!(a != b)); |
||||||
|
Console.WriteLine(!(a > b)); |
||||||
|
|
||||||
|
Console.WriteLine(a + b); |
||||||
|
Console.WriteLine(a - b); |
||||||
|
Console.WriteLine(a * b); |
||||||
|
Console.WriteLine(a / b); |
||||||
|
Console.WriteLine(a % b); |
||||||
|
Console.WriteLine(a & b); |
||||||
|
Console.WriteLine(a | b); |
||||||
|
Console.WriteLine(a ^ b); |
||||||
|
Console.WriteLine(a << i); |
||||||
|
Console.WriteLine(a >> i); |
||||||
|
Console.WriteLine(a ?? b); |
||||||
|
Console.WriteLine(+a); |
||||||
|
Console.WriteLine(-a); |
||||||
|
Console.WriteLine(!a); |
||||||
|
Console.WriteLine(~a); |
||||||
|
// TODO:
|
||||||
|
//Console.WriteLine(a++);
|
||||||
|
//Console.WriteLine(a--);
|
||||||
|
//Console.WriteLine(++a);
|
||||||
|
//Console.WriteLine(--a);
|
||||||
|
//Console.WriteLine((int?)a);
|
||||||
|
a += b; |
||||||
|
a -= b; |
||||||
|
a *= b; |
||||||
|
a /= b; |
||||||
|
a %= b; |
||||||
|
a &= b; |
||||||
|
a |= b; |
||||||
|
a ^= b; |
||||||
|
a <<= i; |
||||||
|
a >>= i; |
||||||
|
} |
||||||
|
|
||||||
|
public static void StructValueComplex(TS? a, Func<TS> x, Func<int> i) |
||||||
|
{ |
||||||
|
Console.WriteLine(a == x()); |
||||||
|
Console.WriteLine(a != x()); |
||||||
|
Console.WriteLine(a > x()); |
||||||
|
|
||||||
|
Console.WriteLine(x() == a); |
||||||
|
Console.WriteLine(x() != a); |
||||||
|
Console.WriteLine(x() > a); |
||||||
|
|
||||||
|
Console.WriteLine(a + x()); |
||||||
|
Console.WriteLine(a - x()); |
||||||
|
Console.WriteLine(a * x()); |
||||||
|
Console.WriteLine(a / x()); |
||||||
|
Console.WriteLine(a % x()); |
||||||
|
Console.WriteLine(a & x()); |
||||||
|
Console.WriteLine(a | x()); |
||||||
|
Console.WriteLine(a ^ x()); |
||||||
|
Console.WriteLine(a << i()); |
||||||
|
Console.WriteLine(a >> i()); |
||||||
|
Console.WriteLine(a ?? x()); |
||||||
|
a += x(); |
||||||
|
a -= x(); |
||||||
|
a *= x(); |
||||||
|
a /= x(); |
||||||
|
a %= x(); |
||||||
|
a &= x(); |
||||||
|
a |= x(); |
||||||
|
a ^= x(); |
||||||
|
a <<= i(); |
||||||
|
a >>= i(); |
||||||
|
|
||||||
|
Console.WriteLine(x() + a); |
||||||
|
(new TS?[0])[0] += x(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// dummy structure for testing custom operators
|
||||||
|
[StructLayout(LayoutKind.Sequential, Size = 1)] |
||||||
|
public struct TS |
||||||
|
{ |
||||||
|
// unary
|
||||||
|
public static TS operator +(TS a) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator -(TS a) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator !(TS a) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator ~(TS a) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator ++(TS a) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator --(TS a) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
|
||||||
|
public static explicit operator int(TS a) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
|
||||||
|
// binary
|
||||||
|
public static TS operator +(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator -(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator *(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator /(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator %(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator &(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator |(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator ^(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator <<(TS a, int b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static TS operator >>(TS a, int b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
|
||||||
|
// comparisons
|
||||||
|
public static bool operator ==(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static bool operator !=(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static bool operator <(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static bool operator <=(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static bool operator >(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public static bool operator >=(TS a, TS b) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool Equals(object obj) |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
public override int GetHashCode() |
||||||
|
{ |
||||||
|
throw null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
|
||||||
|
bin/ |
||||||
|
obj/ |
@ -0,0 +1,95 @@ |
|||||||
|
//
|
||||||
|
// CSharpUtil.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Mike Krüger <mkrueger@novell.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Novell, Inc (http://www.novell.com)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
using System; |
||||||
|
using ICSharpCode.NRefactory.CSharp; |
||||||
|
|
||||||
|
namespace ICSharpCode.NRefactory.CSharp |
||||||
|
{ |
||||||
|
public static class CSharpUtil |
||||||
|
{ |
||||||
|
public static Expression InvertCondition (Expression condition) |
||||||
|
{ |
||||||
|
return InvertConditionInternal (condition.Clone ()); |
||||||
|
} |
||||||
|
|
||||||
|
static Expression InvertConditionInternal (Expression condition) |
||||||
|
{ |
||||||
|
if (condition is ParenthesizedExpression) { |
||||||
|
((ParenthesizedExpression)condition).Expression = InvertCondition (((ParenthesizedExpression)condition).Expression); |
||||||
|
return condition; |
||||||
|
} |
||||||
|
|
||||||
|
if (condition is UnaryOperatorExpression) { |
||||||
|
var uOp = (UnaryOperatorExpression)condition; |
||||||
|
if (uOp.Operator == UnaryOperatorType.Not) |
||||||
|
return uOp.Expression; |
||||||
|
return new UnaryOperatorExpression (UnaryOperatorType.Not, uOp); |
||||||
|
} |
||||||
|
|
||||||
|
if (condition is BinaryOperatorExpression) { |
||||||
|
var bOp = (BinaryOperatorExpression)condition; |
||||||
|
switch (bOp.Operator) { |
||||||
|
case BinaryOperatorType.GreaterThan: |
||||||
|
bOp.Operator = BinaryOperatorType.LessThanOrEqual; |
||||||
|
return bOp; |
||||||
|
case BinaryOperatorType.GreaterThanOrEqual: |
||||||
|
bOp.Operator = BinaryOperatorType.LessThan; |
||||||
|
return bOp; |
||||||
|
case BinaryOperatorType.Equality: |
||||||
|
bOp.Operator = BinaryOperatorType.InEquality; |
||||||
|
return bOp; |
||||||
|
case BinaryOperatorType.InEquality: |
||||||
|
bOp.Operator = BinaryOperatorType.Equality; |
||||||
|
return bOp; |
||||||
|
case BinaryOperatorType.LessThan: |
||||||
|
bOp.Operator = BinaryOperatorType.GreaterThanOrEqual; |
||||||
|
return bOp; |
||||||
|
case BinaryOperatorType.LessThanOrEqual: |
||||||
|
bOp.Operator = BinaryOperatorType.GreaterThan; |
||||||
|
return bOp; |
||||||
|
default: |
||||||
|
return new UnaryOperatorExpression (UnaryOperatorType.Not, new ParenthesizedExpression (condition)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (condition is ConditionalExpression) { |
||||||
|
var cEx = condition as ConditionalExpression; |
||||||
|
cEx.Condition = InvertCondition (cEx.Condition); |
||||||
|
return cEx; |
||||||
|
} |
||||||
|
if (condition is PrimitiveExpression) { |
||||||
|
var pex = condition as PrimitiveExpression; |
||||||
|
if (pex.Value is bool) { |
||||||
|
pex.Value = !((bool)pex.Value); |
||||||
|
return pex; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return new UnaryOperatorExpression (UnaryOperatorType.Not, condition); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,86 @@ |
|||||||
|
//
|
||||||
|
// NamedExpression.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Mike Krüger <mkrueger@xamarin.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011 Xamarin
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
|
||||||
|
namespace ICSharpCode.NRefactory.CSharp |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// name = expression
|
||||||
|
/// This isn't the same as 'assign' even if it has the same syntax. This expression is used in object initializers.
|
||||||
|
/// </summary>
|
||||||
|
public class NamedExpression : Expression |
||||||
|
{ |
||||||
|
public NamedExpression() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public NamedExpression (string identifier, Expression expression) |
||||||
|
{ |
||||||
|
this.Identifier = identifier; |
||||||
|
this.Expression = expression; |
||||||
|
} |
||||||
|
|
||||||
|
public string Identifier { |
||||||
|
get { |
||||||
|
return GetChildByRole (Roles.Identifier).Name; |
||||||
|
} |
||||||
|
set { |
||||||
|
SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, TextLocation.Empty)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Identifier IdentifierToken { |
||||||
|
get { |
||||||
|
return GetChildByRole (Roles.Identifier); |
||||||
|
} |
||||||
|
set { |
||||||
|
SetChildByRole(Roles.Identifier, value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public CSharpTokenNode AssignToken { |
||||||
|
get { return GetChildByRole (Roles.Assign); } |
||||||
|
} |
||||||
|
|
||||||
|
public Expression Expression { |
||||||
|
get { return GetChildByRole (Roles.Expression); } |
||||||
|
set { SetChildByRole (Roles.Expression, value); } |
||||||
|
} |
||||||
|
|
||||||
|
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data = default(T)) |
||||||
|
{ |
||||||
|
return visitor.VisitNamedExpression(this, data); |
||||||
|
} |
||||||
|
|
||||||
|
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) |
||||||
|
{ |
||||||
|
var o = other as NamedExpression; |
||||||
|
return o != null && MatchString(this.Identifier, o.Identifier) && this.Expression.DoMatch(o.Expression, match); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue