static string OutermostValue(ExpressionToCodeConfiguration config, StringifiedExpression node) { if (node.OptionalValue != null) { return(ObjectToCodeImpl.ExpressionValueAsCode(config, node.OptionalValue, 10)); } foreach (var kid in node.Children) { if (!kid.IsConceptualChild) { var value = OutermostValue(config, kid); if (value != null) { return(value); } } } foreach (var kid in node.Children) { if (kid.IsConceptualChild) { var value = OutermostValue(config, kid); if (value != null) { return(value); } } } return(null); }
public static string ComplexObjectToPseudoCode(ExpressionToCodeConfiguration config, object val, int indent) { string retval = ObjectToCode.PlainObjectToCode(val); if (retval != null) { return retval; } else if (val is Array) { return "new[] " + FormatEnumerable(config, (IEnumerable)val, indent); } else if (val is IEnumerable) { return FormatEnumerable(config, (IEnumerable)val, indent); } else if (val is Expression) { return config.GetExpressionToCode().ToCode((Expression)val); } else if (val.GetType().GuessTypeClass() == ReflectionHelpers.TypeClass.AnonymousType) { var type = val.GetType(); return "new {" + string.Join( "", type.GetProperties() .Select( pi => "\n" + new string(' ', indent * 2 + 2) + pi.Name + " = " + ComplexObjectToPseudoCode(config, pi.GetValue(val, null), indent + 2) + ",") ) + "\n" + new string(' ', indent * 2) + "}"; } else { return val.ToString(); } }
static void AppendTo( ExpressionToCodeConfiguration config, StringBuilder sb, List <SubExpressionInfo> nodeInfos, StringifiedExpression node, ref bool ignoreInitialSpace, bool showTopExpressionValue) { if (node.Text != null) { var trimmedText = ignoreInitialSpace ? node.Text.TrimStart() : node.Text; var pos0 = sb.Length; sb.Append(trimmedText); ignoreInitialSpace = node.Text.Any() && ExpressionToCode.ShouldIgnoreSpaceAfter(node.Text[node.Text.Length - 1]); if (showTopExpressionValue) { var valueString = node.OptionalValue == null ? null : ObjectToCodeImpl.ExpressionValueAsCode(config, node.OptionalValue, 0); if (valueString != null) { nodeInfos.Add(new SubExpressionInfo { Location = pos0 + trimmedText.Length / 2, Value = valueString }); } } } foreach (var kid in node.Children) { AppendTo(config, sb, nodeInfos, kid, ref ignoreInitialSpace, showTopExpressionValue || kid.IsConceptualChild); } }
public string AnnotateExpressionTree(ExpressionToCodeConfiguration config, Expression expr, string msg, bool hideOutermostValue) { var splitLine = ExpressionToStringWithValues(config, expr, hideOutermostValue); var exprWithStalkedValues = new StringBuilder(); if (msg == null) { exprWithStalkedValues.AppendLine(splitLine.Line); } else if (IsMultiline(msg)) { exprWithStalkedValues.AppendLine(msg); exprWithStalkedValues.AppendLine(splitLine.Line); } else { exprWithStalkedValues.AppendLine(splitLine.Line + " : " + msg); } for (int nodeI = splitLine.Nodes.Length - 1; nodeI >= 0; nodeI--) { char[] stalkLine = new string('\u2007', splitLine.Nodes[nodeI].Location).ToCharArray(); //figure-spaces. for (int i = 0; i < stalkLine.Length; i++) { if (splitLine.Line[i] == ' ') { stalkLine[i] = ' '; //use normal spaces where the expr used normal spaces for more natural spacing. } } for (int prevI = 0; prevI < nodeI; prevI++) { stalkLine[splitLine.Nodes[prevI].Location] = '\u2502'; //light vertical lines } exprWithStalkedValues.AppendLine((new string(stalkLine) + splitLine.Nodes[nodeI].Value).TrimEnd()); } return exprWithStalkedValues.ToString(); }
static bool?EvalBoolExpr(ExpressionToCodeConfiguration config, Expression e) { try { return(EvalBoolLambda(config, Expression.Lambda <Func <bool> >(e))); } catch (InvalidCastException) { return(null); } }
public static string ToCodeString(ExpressionToCodeConfiguration config, Expression e) { var sb = new StringBuilder(); var ignoreInitialSpace = true; var stringifiedExpr = new ExpressionToCodeImpl(config).ExpressionDispatch(e); AppendTo(sb, ref ignoreInitialSpace, stringifiedExpr); return sb.ToString(); }
static bool?EvalBoolLambda(ExpressionToCodeConfiguration config, Expression <Func <bool> > e) { try { return(EvalBoolFunc(config.Value.ExpressionCompiler.Compile(e))); } catch (InvalidOperationException) { return(null); } }
public static string ToCodeString(ExpressionToCodeConfiguration config, Expression e) { var sb = new StringBuilder(); var ignoreInitialSpace = true; var stringifiedExpr = new ExpressionToCodeImpl(config).ExpressionDispatch(e); AppendTo(sb, ref ignoreInitialSpace, stringifiedExpr); return(sb.ToString()); }
static SplitExpressionLine ExpressionToStringWithValues(ExpressionToCodeConfiguration config, Expression e, bool hideOutermostValue) { var nodeInfos = new List<SubExpressionInfo>(); var sb = new StringBuilder(); bool ignoreInitialSpace = true; var node = new ExpressionToCodeImpl(config).ExpressionDispatch(e); AppendTo(config, sb, nodeInfos, node, ref ignoreInitialSpace, !hideOutermostValue); nodeInfos.Add(new SubExpressionInfo { Location = sb.Length, Value = null }); return new SplitExpressionLine { Line = sb.ToString().TrimEnd(), Nodes = nodeInfos.ToArray() }; }
public static ExpressionWithSubExpressions Create(ExpressionToCodeConfiguration config, Expression e, bool hideOutermostValue) { var sb = new StringBuilder(); bool ignoreInitialSpace = true; var node = new ExpressionToCodeImpl(config).ExpressionDispatch(e); AppendNodeToStringBuilder(sb, node, ref ignoreInitialSpace); var fullExprText = sb.ToString(); var subExpressionValues = new List<SubExpressionValue>(); FindSubExpressionValues(config, node, node, subExpressionValues, hideOutermostValue); return new ExpressionWithSubExpressions { ExpressionString = fullExprText, SubExpressions = subExpressionValues.ToArray() }; }
static string FormatEnumerable(ExpressionToCodeConfiguration config, IEnumerable list, int indent) { var contents = PrintListContents(config, list, indent).ToArray(); if (contents.Sum(s => s.Length) > 100 || contents.Any(s => s.Any(c => c == '\n'))) { var indentString = new string(' ', indent * 2 + 2); return "{\n" + string.Join("", contents.Select(s => indentString + s + (s == "..." ? "" : ",") + "\n")) + new string(' ', indent * 2) + "}"; } return "{" + string.Join(", ", contents) + "}"; }
static IEnumerable<string> PrintListContents(ExpressionToCodeConfiguration config, IEnumerable list, int indent) { int count = 0; foreach (var item in list) { count++; if (count > config.Value.PrintedListLengthLimit) { yield return "..."; yield break; } else { yield return ComplexObjectToPseudoCode(config, item, indent + 4); } } }
static string FormatEnumerable(ExpressionToCodeConfiguration config, IEnumerable list, int indent, int valueSize) { var contents = PrintListContents(config, list, indent).ToArray(); if (contents.Sum(s => s.Length + 2) > Math.Min(valueSize, 120) || contents.Any(s => s.Any(c => c == '\n'))) { return("{" + string.Join("", contents.Select(s => ElidePossiblyMultilineString(config, s, indent + 4, valueSize - 3) + (s == "..." ? "" : ","))) + "\n" + new string(' ', indent) + "}"); } return("{" + string.Join(", ", contents) + "}"); }
static ConstantExpression ToConstantExpr(ExpressionToCodeConfiguration config, Expression e) { try { var func = config.Value.ExpressionCompiler.Compile(Expression.Lambda(e)); try { var val = func.DynamicInvoke(); return(Expression.Constant(val, e.Type)); } catch (Exception) { return(null); //todo:more specific? } } catch (InvalidOperationException) { return(null); } }
static string ComplexObjectToPseudoCode(ExpressionToCodeConfiguration config, object?val, int indent, int valueSize) { var retval = ObjectToCode.PlainObjectToCode(val); if (val is string) { return(ElidePossiblyMultilineString(config, retval ?? throw new InvalidOperationException("retval cannot be null for strings"), indent, valueSize).Trim()); } else if (retval != null) { return(ElideAfter(retval, valueSize)); } else if (val == null) { throw new Exception("Impossible: if val is null, retval cannot be"); } else if (val is Array arrayVal) { return("new[] " + FormatEnumerable(config, arrayVal, indent, valueSize - 6)); } else if (val is IEnumerable enumerableVal) { return(FormatTypeWithListInitializerOrNull(config, val, indent, valueSize, enumerableVal) ?? FormatEnumerable(config, enumerableVal, indent, valueSize)); } else if (val is Expression exprVal) { return(ElideAfter(config.GetExpressionToCode().ToCode(exprVal), valueSize)); } else if (val is IStructuralComparable tuple && val is IComparable && CSharpFriendlyTypeName.IsValueTupleType(val.GetType().GetTypeInfo())) { var collector = new NastyHackyTupleCollector(); tuple.CompareTo(tuple, collector); var sb = new StringBuilder(); sb.Append("("); for (var index = 0; index < collector.CollectedObjects.Count; index++) { var item = collector.CollectedObjects[index]; var asString = ComplexObjectToPseudoCode(config, item, indent + 4, valueSize); if (index > 0) { sb.Append(", "); } sb.Append(asString); } sb.Append(")"); return(ElidePossiblyMultilineString(config, sb.ToString(), indent, valueSize).Trim()); }
public static ExpressionWithSubExpressions Create(ExpressionToCodeConfiguration config, Expression e, bool hideOutermostValue) { var sb = new StringBuilder(); var ignoreInitialSpace = true; var node = new ExpressionToCodeImpl(config).ExpressionDispatch(e); AppendNodeToStringBuilder(sb, node, ref ignoreInitialSpace); var fullExprText = sb.ToString(); var subExpressionValues = new List <SubExpressionValue>(); FindSubExpressionValues(config, node, node, subExpressionValues, hideOutermostValue); return(new ExpressionWithSubExpressions { ExpressionString = fullExprText, SubExpressions = subExpressionValues.Distinct().ToArray() }); }
static SplitExpressionLine ExpressionToStringWithValues(ExpressionToCodeConfiguration config, Expression e, bool outerValueIsAssertionFailure) { var nodeInfos = new List <SubExpressionInfo>(); var sb = new StringBuilder(); var ignoreInitialSpace = true; var node = new ExpressionToCodeImpl(config).ExpressionDispatch(e); AppendTo(config, sb, nodeInfos, node, ref ignoreInitialSpace, !outerValueIsAssertionFailure); nodeInfos.Add(new SubExpressionInfo { Location = sb.Length, Value = null }); return(new SplitExpressionLine { Line = sb.ToString().TrimEnd(), Nodes = nodeInfos.ToArray() }); }
static void AppendTo(ExpressionToCodeConfiguration config, StringBuilder sb, List<SubExpressionInfo> nodeInfos, StringifiedExpression node, ref bool ignoreInitialSpace, bool showTopExpressionValue) { if (node.Text != null) { var trimmedText = ignoreInitialSpace ? node.Text.TrimStart() : node.Text; var pos0 = sb.Length; sb.Append(trimmedText); ignoreInitialSpace = node.Text.Any() && ExpressionToCode.ShouldIgnoreSpaceAfter(node.Text[node.Text.Length - 1]); if (showTopExpressionValue) { string valueString = node.OptionalValue == null ? null : ObjectToCodeImpl.ExpressionValueAsCode(config, node.OptionalValue); if (valueString != null) { nodeInfos.Add(new SubExpressionInfo { Location = pos0 + trimmedText.Length / 2, Value = valueString }); } } } foreach (var kid in node.Children) { AppendTo(config, sb, nodeInfos, kid, ref ignoreInitialSpace, showTopExpressionValue || kid.IsConceptualChild); } }
static string ElidePossiblyMultilineString(ExpressionToCodeConfiguration config, string val, int indent, int len) { var lines = val.Split(lineSeparators, StringSplitOptions.None); var indentString = new string(' ', indent); if (lines.Length < 2) { return("\n" + indentString + ElideAfter(val, len)); } if (config.Value.PrintedListLengthLimit is int limit && lines.Length > limit) { lines = lines.Take(limit).Concat(new[] { "..." }).ToArray(); } var stringBoundaryPrefix = lines[0].StartsWith("@\"") ? 2 : lines[0].StartsWith("\"") ? 1 : 0; var firstLineIndent = "\n" + indentString.Substring(0, Math.Max(0, indentString.Length - stringBoundaryPrefix)); return(firstLineIndent + string.Join("\n" + indentString, lines.Select(s => ElideAfter(s, len - 1)))); }
static string ComplexObjectToPseudoCode(ExpressionToCodeConfiguration config, object val, int indent, int valueSize) { var retval = ObjectToCode.PlainObjectToCode(val); if (val is string) { return(ElidePossiblyMultilineString(config, retval, indent, valueSize).Trim()); } else if (retval != null) { return(ElideAfter(retval, valueSize)); } else if (val is Array) { return("new[] " + FormatEnumerable(config, (IEnumerable)val, indent, valueSize - 6)); } else if (val is IEnumerable) { return(FormatEnumerable(config, (IEnumerable)val, indent, valueSize)); } else if (val is Expression) { return(ElideAfter(config.GetExpressionToCode().ToCode((Expression)val), valueSize)); } else if (val.GetType().GuessTypeClass() == ReflectionHelpers.TypeClass.AnonymousType) { var type = val.GetType(); return("new {" + string.Join( "", type.GetTypeInfo() .GetProperties() .Select( pi => "\n" + new string(' ', indent + 4) + pi.Name + " = " + ComplexObjectToPseudoCode(config, pi.GetValue(val, null), indent + 4, valueSize - pi.Name.Length) + ",") ) + "\n" + new string(' ', indent) + "}"); } else { return(ElideAfter(val.ToString(), valueSize)); } }
static void FindSubExpressionValues( ExpressionToCodeConfiguration config, StringifiedExpression node, StringifiedExpression subExprNode, List <SubExpressionValue> subExpressionValues, bool outerValueIsAssertionFailure) { if (!outerValueIsAssertionFailure && node.OptionalValue != null) { var sb = new StringBuilder(); var ignoreInitialSpace = true; var valueString = ObjectToCodeImpl.ExpressionValueAsCode(config, node.OptionalValue, 10); AppendNodeToStringBuilder(sb, subExprNode, ref ignoreInitialSpace); var maxSize = Math.Max(40, config.Value.MaximumValueLength ?? 200); var subExprString = sb.Length <= maxSize ? sb.ToString() : sb.ToString(0, maxSize / 2 - 1) + " … " + sb.ToString(sb.Length - (maxSize / 2 - 1), maxSize / 2 - 1); // ReSharper disable once ReplaceWithStringIsNullOrEmpty - for nullability analysis if (valueString != null && valueString != "") { subExpressionValues.Add(new SubExpressionValue { SubExpression = subExprString, ValueAsString = valueString }); } } foreach (var kid in node.Children) { if (!kid.IsConceptualChild) { FindSubExpressionValues(config, kid, subExprNode, subExpressionValues, outerValueIsAssertionFailure); } } foreach (var kid in node.Children) { if (kid.IsConceptualChild) { FindSubExpressionValues(config, kid, kid, subExpressionValues, false); } } }
public static ExpressionWithSubExpressions Create(ExpressionToCodeConfiguration config, Expression e, bool outerValueIsAssertionFailure) { var sb = new StringBuilder(); var ignoreInitialSpace = true; var node = new ExpressionToCodeImpl(config).ExpressionDispatch(e); AppendNodeToStringBuilder(sb, node, ref ignoreInitialSpace); var fullExprText = sb.ToString(); var subExpressionValues = new List <SubExpressionValue>(); FindSubExpressionValues(config, node, node, subExpressionValues, outerValueIsAssertionFailure); var assertionValue = outerValueIsAssertionFailure? OutermostValue(config, node) : null; return(new ExpressionWithSubExpressions { ExpressionString = fullExprText + (assertionValue != null ? "\n" + spacedArrow + assertionValue + " (caused assertion failure)\n" :""), SubExpressions = subExpressionValues.Distinct().ToArray() }); }
static IEnumerable <string> PrintInitializerContents(ExpressionToCodeConfiguration config, IEnumerable <KeyValuePair <TKey, TValue> > list) { var count = 0; foreach (var item in list) { count++; if (count > config.Value.PrintedListLengthLimit) { yield return("..."); yield break; } else { yield return($"[{ComplexObjectToPseudoCode(config, item.Key, 0)}] = {ComplexObjectToPseudoCode(config, item.Value, 0)}"); } } }
static IEnumerable <string> PrintListContents(ExpressionToCodeConfiguration config, IEnumerable list, int indent) { var count = 0; foreach (var item in list) { count++; if (count > config.Value.PrintedListLengthLimit) { yield return("..."); yield break; } else { yield return(ComplexObjectToPseudoCode(config, item, 0)); } } }
public static string ExpressionValueAsCode(ExpressionToCodeConfiguration config, Expression expression, int indent) { try { Delegate lambda; try { lambda = config.Value.ExpressionCompiler.Compile(Expression.Lambda(expression)); } catch (InvalidOperationException) { return(null); } var val = lambda.DynamicInvoke(); try { return(ComplexObjectToPseudoCode(config, val, indent)); } catch (Exception e) { return("stringification throws " + e.GetType().FullName); } } catch (TargetInvocationException tie) { return("throws " + tie.InnerException.GetType().FullName); } }
public static string ExpressionValueAsCode(ExpressionToCodeConfiguration config, Expression expression) { try { Delegate lambda; try { lambda = Expression.Lambda(expression).Compile(); } catch (InvalidOperationException) { return null; } var val = lambda.DynamicInvoke(); try { return ObjectToCodeImpl.ComplexObjectToPseudoCode(config, val, 0); } catch (Exception e) { return "stringification throws " + e.GetType().FullName; } } catch (TargetInvocationException tie) { return "throws " + tie.InnerException.GetType().FullName; } }
public string AnnotateExpressionTree(ExpressionToCodeConfiguration config, Expression expr, string?msg, bool outerValueIsAssertionFailure) { var splitLine = ExpressionToStringWithValues(config, expr, outerValueIsAssertionFailure); var exprWithStalkedValues = new StringBuilder(); if (msg == null) { exprWithStalkedValues.AppendLine(splitLine.Line); } else if (IsMultiline(msg)) { exprWithStalkedValues.AppendLine(msg); exprWithStalkedValues.AppendLine(splitLine.Line); } else { exprWithStalkedValues.AppendLine(splitLine.Line + " : " + msg); } for (var nodeI = splitLine.Nodes.Length - 1; nodeI >= 0; nodeI--) { var stalkLine = new string('\u2007', splitLine.Nodes[nodeI].Location).ToCharArray(); //figure-spaces. for (var i = 0; i < stalkLine.Length; i++) { if (splitLine.Line[i] == ' ') { stalkLine[i] = ' '; //use normal spaces where the expr used normal spaces for more natural spacing. } } for (var prevI = 0; prevI < nodeI; prevI++) { stalkLine[splitLine.Nodes[prevI].Location] = '\u2502'; //light vertical lines } exprWithStalkedValues.AppendLine((new string(stalkLine) + splitLine.Nodes[nodeI].Value).TrimEnd()); } return(exprWithStalkedValues.ToString()); }
static void FindSubExpressionValues( ExpressionToCodeConfiguration config, StringifiedExpression node, StringifiedExpression subExprNode, List <SubExpressionValue> subExpressionValues, bool hideOutermostValue) { if (!hideOutermostValue && node.OptionalValue != null) { var sb = new StringBuilder(); var ignoreInitialSpace = true; var valueString = ObjectToCodeImpl.ExpressionValueAsCode(config, node.OptionalValue, 10); AppendNodeToStringBuilder(sb, subExprNode, ref ignoreInitialSpace); var maxSize = 80; var subExprString = sb.Length <= maxSize ? sb.ToString() : sb.ToString(0, maxSize / 2 - 1) + " … " + sb.ToString(sb.Length - (maxSize / 2 - 1), maxSize / 2 - 1); if (!string.IsNullOrEmpty(valueString)) { subExpressionValues.Add(new SubExpressionValue { SubExpression = subExprString, ValueAsString = valueString }); } } foreach (var kid in node.Children) { if (kid.IsConceptualChild) { FindSubExpressionValues(config, kid, kid, subExpressionValues, false); } } foreach (var kid in node.Children) { if (!kid.IsConceptualChild) { FindSubExpressionValues(config, kid, subExprNode, subExpressionValues, hideOutermostValue); } } }
static void FindSubExpressionValues( ExpressionToCodeConfiguration config, StringifiedExpression node, StringifiedExpression subExprNode, List<SubExpressionValue> subExpressionValues, bool hideOutermostValue) { if (!hideOutermostValue && node.OptionalValue != null) { var sb = new StringBuilder(); var ignoreInitialSpace = true; AppendNodeWithLimitedDepth(sb, subExprNode, ref ignoreInitialSpace, 2); var subExprString = sb.ToString(); string valueString = ObjectToCodeImpl.ExpressionValueAsCode(config, node.OptionalValue); subExpressionValues.Add(new SubExpressionValue { SubExpression = subExprString, ValueAsString = valueString }); } foreach (var kid in node.Children) { if (kid.IsConceptualChild) { FindSubExpressionValues(config, kid, kid, subExpressionValues, false); } else { FindSubExpressionValues(config, kid, subExprNode, subExpressionValues, hideOutermostValue); } } }
public string AnnotateExpressionTree(ExpressionToCodeConfiguration config, Expression expr, string msg, bool outerValueIsAssertionFailure) => (msg == null ? "" : msg + "\n\n") + ExpressionWithSubExpressions.Create(config, expr, outerValueIsAssertionFailure).ComposeToSingleString();
public string AnnotateExpressionTree(ExpressionToCodeConfiguration config, Expression expr, string msg, bool hideOutermostValue) { return (msg == null ? "" : msg + "\n") + ExpressionWithSubExpressions.Create(config, expr, hideOutermostValue).ComposeToSingleString(); }
static IEnumerable <Tuple <EqualityExpressionClass, bool> > DisagreeingEqualities( ExpressionToCodeConfiguration config, Expression left, Expression right, bool shouldBeEqual) { var leftC = ToConstantExpr(config, left); var rightC = ToConstantExpr(config, right); Tuple <EqualityExpressionClass, bool> ReportIfError(EqualityExpressionClass eqClass, bool?itsVal) => shouldBeEqual == itsVal ? null : Tuple.Create(eqClass, !itsVal.HasValue); var ienumerableTypes = GetGenericInterfaceImplementation(leftC.Type, typeof(IEnumerable <>)) .Intersect(GetGenericInterfaceImplementation(rightC.Type, typeof(IEnumerable <>))) .Select(seqType => seqType.GetTypeInfo().GetGenericArguments().Single()); var seqEqualsMethod = ((Func <IEnumerable <int>, IEnumerable <int>, bool>)Enumerable.SequenceEqual).GetMethodInfo().GetGenericMethodDefinition(); var iequatableEqualsMethods = (from genEquatable in GetGenericInterfaceImplementation(leftC.Type, typeof(IEquatable <>)) let otherType = genEquatable.GetTypeInfo().GetGenericArguments().Single() where otherType.GetTypeInfo().IsAssignableFrom(rightC.Type) let ifacemap = leftC.Type.GetTypeInfo().GetRuntimeInterfaceMap(genEquatable) select ifacemap.InterfaceMethods.Zip(ifacemap.InterfaceMethods, Tuple.Create) .Single(ifaceAndImpl => ifaceAndImpl.Item1.Name == "Equals") .Item2).Distinct(); var errs = new[] { ReportIfError(EqualityExpressionClass.EqualsOp, EvalBoolExpr(config, Expression.Equal(leftC, rightC))), ReportIfError(EqualityExpressionClass.NotEqualsOp, EvalBoolExpr(config, Expression.Not(Expression.NotEqual(leftC, rightC)))), ReportIfError( EqualityExpressionClass.ObjectEquals, EvalBoolExpr(config, Expression.Call(leftC, objEqualInstanceMethod, Expression.Convert(rightC, typeof(object))))), ReportIfError( EqualityExpressionClass.ObjectEqualsStatic, EvalBoolExpr( config, Expression.Call( objEqualStaticMethod, Expression.Convert(leftC, typeof(object)), Expression.Convert(rightC, typeof(object))))), ReportIfError(EqualityExpressionClass.ObjectReferenceEquals, object.ReferenceEquals(leftC.Value, rightC.Value)), ReportIfError( EqualityExpressionClass.StructuralEquals, StructuralComparisons.StructuralEqualityComparer.Equals(leftC.Value, rightC.Value)), }.Concat( iequatableEqualsMethods.Select( method => ReportIfError( EqualityExpressionClass.EquatableEquals, EvalBoolExpr( config, Expression.Call(leftC, method, rightC)))) ) .Concat( ienumerableTypes.Select( elemType => ReportIfError( EqualityExpressionClass.SequenceEqual, EvalBoolExpr( config, Expression.Call(seqEqualsMethod.MakeGenericMethod(elemType), leftC, rightC)))) ); return(errs.Where(err => err != null).Distinct().ToArray()); }
public static IEnumerable <Tuple <EqualityExpressionClass, bool> > DisagreeingEqualities(ExpressionToCodeConfiguration config, Expression <Func <bool> > e) { var currEquals = ExtractEqualityType(e); if (currEquals.Item1 == EqualityExpressionClass.None) { return(null); } var currVal = EvalBoolLambda(config, e); if (!currVal.HasValue) { return(null); } return(DisagreeingEqualities(config, currEquals.Item2, currEquals.Item3, currVal.Value)); }
public IEnumerable <string> PrintInitializerContents(ExpressionToCodeConfiguration config, IEnumerable list) => PrintInitializerContents(config, (IEnumerable <KeyValuePair <TKey, TValue> >)list);
public ExpressionToCodeImpl(ExpressionToCodeConfiguration config) => this.config = config;
static string ComplexObjectToPseudoCode(ExpressionToCodeConfiguration config, object val, int indent, int valueSize) { var retval = ObjectToCode.PlainObjectToCode(val); if (val is string) { return(ElidePossiblyMultilineString(config, retval, indent, valueSize).Trim()); } else if (retval != null) { return(ElideAfter(retval, valueSize)); } else if (val is Array arrayVal) { return("new[] " + FormatEnumerable(config, arrayVal, indent, valueSize - 6)); } else if (val is IEnumerable enumerableVal) { var type = val.GetType(); if (type.GetConstructor(Type.EmptyTypes) is ConstructorInfo ci && ci.IsPublic) { foreach (var pi in type.GetProperties()) { if ( pi.Name == "Item" && pi.CanWrite && pi.GetIndexParameters() is ParameterInfo[] indexPars && indexPars.Length == 1 && typeof(IEnumerable <>).MakeGenericType(typeof(KeyValuePair <,>).MakeGenericType(indexPars[0].ParameterType, pi.PropertyType)) is Type keyEnumerableType && keyEnumerableType.IsAssignableFrom(type) ) { var typeName = type.ToCSharpFriendlyTypeName(); return("new " + typeName + " " + PrintInitializerContents(config, enumerableVal, indexPars[0].ParameterType, pi.PropertyType, indent, valueSize - typeName.Length)); } } } return(FormatEnumerable(config, enumerableVal, indent, valueSize)); } else if (val is Expression exprVal) { return(ElideAfter(config.GetExpressionToCode().ToCode(exprVal), valueSize)); } else if (val is IStructuralComparable tuple && val is IComparable && CSharpFriendlyTypeName.IsValueTupleType(val.GetType().GetTypeInfo())) { var collector = new NastyHackyTupleCollector(); tuple.CompareTo(tuple, collector); var sb = new StringBuilder(); sb.Append("("); for (var index = 0; index < collector.CollectedObjects.Count; index++) { var item = collector.CollectedObjects[index]; var asString = ComplexObjectToPseudoCode(config, item, indent + 4, valueSize); if (index > 0) { sb.Append(", "); } sb.Append(asString); } sb.Append(")"); return(ElidePossiblyMultilineString(config, sb.ToString(), indent, valueSize).Trim()); }
public static string ComplexObjectToPseudoCode(ExpressionToCodeConfiguration config, object?val, int indent) => ComplexObjectToPseudoCode(config, val, indent, config.Value.MaximumValueLength ?? int.MaxValue);
public static IEnumerable <Tuple <EqualityExpressionClass, bool> >?DisagreeingEqualities(ExpressionToCodeConfiguration config, Expression <Func <bool> > e) { var currEquals = ExtractEqualityType(e); if (currEquals == null) { return(null); } var currVal = EvalBoolLambda(config, e); if (!currVal.HasValue) { return(null); } return(DisagreeingEqualities(config, currEquals.Value.left, currEquals.Value.right, currVal.Value) .Select(o => o.ToTuple())//purely to avoid breaking API changes ); }
public string AnnotateExpressionTree(ExpressionToCodeConfiguration config, Expression expr, string msg, bool hideOutermostValue) => (msg == null ? "" : msg + "\n\n") + ExpressionWithSubExpressions.Create(config, expr, hideOutermostValue).ComposeToSingleString();