|
| 1 | +using ExpressionToString.Util; |
| 2 | +using System; |
| 3 | +using System.Collections.Generic; |
| 4 | +using System.Dynamic; |
| 5 | +using System.Linq; |
| 6 | +using System.Linq.Expressions; |
| 7 | +using System.Runtime.CompilerServices; |
| 8 | +using System.Text; |
| 9 | +using System.Threading.Tasks; |
| 10 | +using static ExpressionToString.Util.Functions; |
| 11 | +using static ExpressionToString.Globals; |
| 12 | +using System.Collections; |
| 13 | + |
| 14 | +namespace ExpressionToString { |
| 15 | + public class TextualTreeFormatter : WriterBase { |
| 16 | + public TextualTreeFormatter(object o, string language) : base(o, language) { } |
| 17 | + |
| 18 | + public TextualTreeFormatter(object o, string language, out Dictionary<string, (int start, int length)> pathSpans) : base(o, language, out pathSpans) { } |
| 19 | + |
| 20 | + private void WriteTextualNode(object o) { |
| 21 | + var nodeType = ""; |
| 22 | + var typename = ""; |
| 23 | + var name = ""; |
| 24 | + object value = null; |
| 25 | + |
| 26 | + switch (o) { |
| 27 | + case Expression expr: |
| 28 | + nodeType = expr.NodeType.ToString(); |
| 29 | + typename = $"({expr.Type.FriendlyName(language)})"; |
| 30 | + name = expr.Name(); |
| 31 | + |
| 32 | + switch (expr) { |
| 33 | + case ConstantExpression cexpr when !expr.Type.IsClosureClass(): |
| 34 | + value = cexpr.Value; |
| 35 | + break; |
| 36 | + case Expression _ when expr.IsClosedVariable(): |
| 37 | + case DefaultExpression _: |
| 38 | + value = expr.ExtractValue(); |
| 39 | + break; |
| 40 | + } |
| 41 | + break; |
| 42 | + |
| 43 | + case MemberBinding mbind: |
| 44 | + nodeType = mbind.BindingType.ToString(); |
| 45 | + name = mbind.Member.Name; |
| 46 | + break; |
| 47 | + case CallSiteBinder binder: |
| 48 | + nodeType = binder.BinderType(); |
| 49 | + break; |
| 50 | + default: |
| 51 | + nodeType = o.GetType().FriendlyName(language); |
| 52 | + break; |
| 53 | + } |
| 54 | + |
| 55 | + string stringValue = ""; |
| 56 | + if (value != null) { stringValue = "= " + StringValue(value, language); } |
| 57 | + |
| 58 | + Write((nodeType, typename, name, stringValue).Where(x => !x.IsNullOrWhitespace()).Joined(" ")); |
| 59 | + |
| 60 | + var type = o.GetType(); |
| 61 | + var preferredOrder = PreferredPropertyOrders.FirstOrDefault(x => x.type.IsAssignableFrom(o.GetType())).propertyNames; |
| 62 | + var childNodes = type.GetProperties() |
| 63 | + .Where(prp => |
| 64 | + prp.PropertyType.InheritsFromOrImplementsAny(PropertyTypes) || |
| 65 | + prp.PropertyType.InheritsFromOrImplementsAny(NodeTypes) |
| 66 | + ) |
| 67 | + .OrderBy(x => { |
| 68 | + if (preferredOrder == null) { return -1; } |
| 69 | + return Array.IndexOf(preferredOrder, x.Name); |
| 70 | + }) |
| 71 | + .ThenBy(x => x.Name) |
| 72 | + .SelectMany(prp => { |
| 73 | + if (prp.PropertyType.InheritsFromOrImplements<IEnumerable>()) { |
| 74 | + return (prp.GetValue(o) as IEnumerable).Cast<object>().Select((x, index) => (name: $"{prp.Name}[{index}]", value: x)); |
| 75 | + } else { |
| 76 | + return new[] { (prp.Name, prp.GetValue(o)) }; |
| 77 | + } |
| 78 | + }) |
| 79 | + .Where(x => x.value != null) |
| 80 | + .ToList(); |
| 81 | + |
| 82 | + if (childNodes.Any()) { |
| 83 | + Indent(); |
| 84 | + WriteEOL(); |
| 85 | + childNodes.ForEach((node, index) => { |
| 86 | + if (index > 0) { WriteEOL(); } |
| 87 | + Write(node.name); |
| 88 | + Write(" -- "); |
| 89 | + WriteNode(node); |
| 90 | + }); |
| 91 | + Dedent(); |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + protected override void WriteBinary(BinaryExpression expr) => WriteTextualNode(expr); |
| 96 | + protected override void WriteUnary(UnaryExpression expr) => WriteTextualNode(expr); |
| 97 | + protected override void WriteLambda(LambdaExpression expr) => WriteTextualNode(expr); |
| 98 | + protected override void WriteParameter(ParameterExpression expr) => WriteTextualNode(expr); |
| 99 | + protected override void WriteConstant(ConstantExpression expr) => WriteTextualNode(expr); |
| 100 | + protected override void WriteMemberAccess(MemberExpression expr) => WriteTextualNode(expr); |
| 101 | + protected override void WriteNew(NewExpression expr) => WriteTextualNode(expr); |
| 102 | + protected override void WriteCall(MethodCallExpression expr) => WriteTextualNode(expr); |
| 103 | + protected override void WriteMemberInit(MemberInitExpression expr) => WriteTextualNode(expr); |
| 104 | + protected override void WriteListInit(ListInitExpression expr) => WriteTextualNode(expr); |
| 105 | + protected override void WriteNewArray(NewArrayExpression expr) => WriteTextualNode(expr); |
| 106 | + protected override void WriteConditional(ConditionalExpression expr, object metadata) => WriteTextualNode(expr); |
| 107 | + protected override void WriteDefault(DefaultExpression expr) => WriteTextualNode(expr); |
| 108 | + protected override void WriteTypeBinary(TypeBinaryExpression expr) => WriteTextualNode(expr); |
| 109 | + protected override void WriteInvocation(InvocationExpression expr) => WriteTextualNode(expr); |
| 110 | + protected override void WriteIndex(IndexExpression expr) => WriteTextualNode(expr); |
| 111 | + protected override void WriteBlock(BlockExpression expr, object metadata) => WriteTextualNode(expr); |
| 112 | + protected override void WriteSwitch(SwitchExpression expr) => WriteTextualNode(expr); |
| 113 | + protected override void WriteTry(TryExpression expr) => WriteTextualNode(expr); |
| 114 | + protected override void WriteLabel(LabelExpression expr) => WriteTextualNode(expr); |
| 115 | + protected override void WriteGoto(GotoExpression expr) => WriteTextualNode(expr); |
| 116 | + protected override void WriteLoop(LoopExpression expr) => WriteTextualNode(expr); |
| 117 | + protected override void WriteRuntimeVariables(RuntimeVariablesExpression expr) => WriteTextualNode(expr); |
| 118 | + protected override void WriteDebugInfo(DebugInfoExpression expr) => WriteTextualNode(expr); |
| 119 | + protected override void WriteElementInit(ElementInit elementInit) => WriteTextualNode(elementInit); |
| 120 | + protected override void WriteBinding(MemberBinding binding) => WriteTextualNode(binding); |
| 121 | + protected override void WriteSwitchCase(SwitchCase switchCase) => WriteTextualNode(switchCase); |
| 122 | + protected override void WriteCatchBlock(CatchBlock catchBlock) => WriteTextualNode(catchBlock); |
| 123 | + protected override void WriteLabelTarget(LabelTarget labelTarget) => WriteTextualNode(labelTarget); |
| 124 | + protected override void WriteDynamic(DynamicExpression expr) => WriteTextualNode(expr); |
| 125 | + protected override void WriteBinaryOperationBinder(BinaryOperationBinder binaryOperationBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 126 | + protected override void WriteConvertBinder(ConvertBinder convertBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 127 | + protected override void WriteCreateInstanceBinder(CreateInstanceBinder createInstanceBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 128 | + protected override void WriteDeleteIndexBinder(DeleteIndexBinder deleteIndexBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 129 | + protected override void WriteDeleteMemberBinder(DeleteMemberBinder deleteMemberBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 130 | + protected override void WriteGetIndexBinder(GetIndexBinder getIndexBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 131 | + protected override void WriteGetMemberBinder(GetMemberBinder getMemberBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 132 | + protected override void WriteInvokeBinder(InvokeBinder invokeBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 133 | + protected override void WriteInvokeMemberBinder(InvokeMemberBinder invokeMemberBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 134 | + protected override void WriteSetIndexBinder(SetIndexBinder setIndexBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 135 | + protected override void WriteSetMemberBinder(SetMemberBinder setMemberBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 136 | + protected override void WriteUnaryOperationBinder(UnaryOperationBinder unaryOperationBinder, IList<Expression> args) => throw new NotImplementedException(); |
| 137 | + protected override void WriteParameterDeclarationImpl(ParameterExpression prm) => throw new NotImplementedException(); |
| 138 | + } |
| 139 | +} |
0 commit comments