Code Monkey home page Code Monkey logo

expressiontreevisualizer's People

Contributors

hjkl950217 avatar zspitz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

expressiontreevisualizer's Issues

Render ConstantExpression containing an array as array literal

For example:

Constant(new [] { 1, 2, 3 })

should render as:

new [] { 1, 2, 3 }

instead of:

#Int32[]

Even arrays of unrenderable values could be rendered:

new [] { #Random, #Random, #Random }

If all the elements have the same type as the array use implicit array type. Otherwise, use the explicit array type:

new object [] { #Random, #Random, #Random }

Extend visualizer tree and formatters for expressions which return Expression

e.g. ConstantExpression whose value is an Expression, or MemberAccessExpression.

The value of the expression can be extracted using ExtractValue.

For ConstantExpression, we could add a node for the Value property. Other expressions would need a virtual (Value) node.

We'd have to make sure that there are no ParameterExpressions within the expression we're evaluating.

Implement selection sync between tree, source code, and end nodes pane

Source of truth of current selection is the tree -- selection of the tree node selects the text in the source code, and (when appropriate) selects the relevant end node.
Selecting either the source code or the end node will reflect back in the tree.

  • Selection in tree -> select text in source
  • Selection in tree -> if an end node, select in the appropriate grid; else deselect all
  • Selection of end node -> select in tree
  • Selection of source code -> select in tree

Render ValueTuple

Only when ConstantExpression

Currently, value tuple cannot be written in an expression

Copy treenode path to clipboard

Copy icon on hover for every node
path to selected node when pasted in Watch window / immediate window
child expressions need to be strongly typed to the appropriate expression type

(((expr as LambdaExpression).Body as BinaryExpression).Left as UnaryExpression).Operand

Will require #2


For now:

  • path will be written based on the current formatter
  • textbox with base expression, to be filled in by the user
  • when running this command, if the textbox is empty, prompt the user for the value to fill it with

Closed over variables

Within mapper:
maintain a list of tuples - closure id, name, type

in visualizer:
display an expander for each closure id; each expander will have a list of names and types
enable copying expression to extract current value in Watch window (wrap in LambdaExpression and invoke)

Visualizer error handling

Any exceptions that only affect the source code generation will show up in the source code as a new line with some details about the exception.

----- NotImplementedException - NodeType: AddAssign, Expression object type: SimpleBinaryExpression ()

But if there is an exception while generating the VisualizerData, then we should display instead of the regular UI, a special exception UI, with 1) the DebugView of the expression, 2) the ToString using the factory methods formatter (#38) and 3) a link to create an issue on GitHub with these details filled in.

Implement MultiSelectTreeView control

Currently using https://unclassified.software/en/source/multiselecttreeview, and I also looked at https://github.com/cmyksvoll/MultiSelectTreeView

Required features:

  • Multiple selection support
  • .NET Core support
  • Enable applying focused styling even when the control does not have the focus (like we do for built-in WPF controls)
  • NuGet package (alternatively, include the control in ZSpitz.Utils.Wpf)

Nice to have:

  • Selected Values and SelectedValuePath methods
  • Allows simply assigning items/values to SelectedItems / SelectedValues (see below)
  • No editing not required or fancy selection behavior; makes it easier to debug incompatibility issues
  • Optional lazy loading support (although that could be part of the view-model if need be)

Auto-filing of issues

Two use cases:

  1. Parts not implemented in code-gen
  2. Exceptions in general

Allow the user to click on a URL from the visualizer UI, and autofill an issue.

Deploy as VSIX

The recommended way to install a custom visualizer is simply to copy the DLL into the appropriate Visualizers folder. This can be either the Visual Studio install path, or within My Documents.

It's possible to use a VSIX for this purpose -- enclose the visualizer DLL in the VSIX package; and each time the application loads, check if the visualizer has been installed from the package; and if not, copy the file. This is not a really good solution, because every visualizer developer has to reimplement it for their VSIX.

I think a better solution would be to create an extension to manage visualizers. On load, it would go over each VSIX package and find visualizers (indicate the visualizer in the package somehow? in the package metadata? Checking all the DLLs for a reference to Microsoft.Debugger.Visualizer.DLL doesn't make sense). Then it would check the target folder (whether this particular visualizer should prefer VS-level installation if possible, or per-user installation might be part of the metadata of the package), and if the visualizer isn't in the target folder, or an older version is in the target folder, it would copy over the visualizer.

A natural part of this extension could be a way to manage visualizers:

  • grid view - location, per VS instance / per user, filename, visualizer title, visualized type, (delete), (browse location)
  • tree view - grouped by location, physical file
  • buttons - install visualizer from file, install from VSIX

The information could be extracted from the DLLs, or from .natvis files.

Then, individual visualizer authors could include the visualizer in a VSIX with appropriate metadata, list the above extension as a dependency, and everything else would happen automatically.

List of types in System.Linq.Expressions to be rendered

Packaging and deployment

  • Nuget package for converting expression trees and expression tree parts (#41 ) to strings
  • Setup automatic deployment to NuGet on commit with AppVeyor
  • Setup GitHub releases?
  • Setup automatic deployment to GitHub releases using AppVeyor

Making the visualizer available as a VSIX package is problematic; see #44.

Leverage VS controls

For example, the Solution Explorer is a multiselect treeview, which could be used instead of a third party component.

Minor UI enhancements -- pure UI

  • Expand all nodes by default on first load
  • Reformat root node so it doesn't start with a hyphen
  • More polished formatting (some padding/margins etc.)
  • Use the same selection style across all tree, source and datagrids

Drop Roslyn for code generation

  1. https://stackoverflow.com/questions/54171930/this-function-requires-all-threads-to-evaluate-after-new-adhocworkspace-wi
  2. Including the full Roslyn compiler greatly increases the install size, and I suspect that all the Roslyn assemblies and their dependencies have to be installed in the GAC, for security.
  3. The SyntaxNode API is not fully cross-language; there are a number of places where we anyway have to drop down to the individual syntax factories.

This involves three classes: an abstract base class with methods for writing to a StringBuilder based on a given expression or other part (such as MemberBinding or ElementInit), and language-specific implementations for C# and VB.NET,

A single ParameterExpression can be used multiple times within an expression tree

Object.ReferenceEquals returns true when comparing both ParameterExpression objects that refer to the same parameter.

We were originally using an Dictionary<object, (int start, int length)> to hold the span corresponding to the Expression or other part of the expression tree. ParameterExpression instances will only exist in the dictionary once, even though they may be used multiple times in the expression tree; the ParameterExpression would return the same (start, length) anywhere it was used in the expression tree.

The current workaround is to using a Dictionary<object, List<(int start, int length)>; only for ParameterExpression is there more than one item in the list. And we're figuring out which (start, length) is the right one, by passing in the parent (start, length) and finding the (start, length) that fall's within the parent's (start, length).

But this falls down if the same ParameterExpression is set as two of the direct children of the node.

A solution to this would be to define the order of properties traversed in the formatter for a given node, and to follow that order when generating the visualizer data; thus we could know "this is the first instance of ParameterExpression as a child of the current node; this is the second` and match them up to the appropriate properties. (I prefer this because it means we're using a simpler data structure.)

Some other possible solutions:

  • The key of the dictionary should be the path to the expression, instead of the expression itself -- Body.Call.Argument1. This assumes the formatter is walking the expression tree just like the visualizer data generation is; probably a valid assumption, but we'd have to verify it.
  • The List<(start, length)> should become a Dictionary<string, (start, length)>, and instead of passing the parent (start, length), we could pass in the parent's property which is the path to the current node -- Dictionary<string, (start, length)>.

Expression Quoter code writer

Shows the calls to the factory methods needed to construct the expression

Variant for C# and for VB.NET

Assumes using/Imports System.Linq.Expressions.Expression

Improvements to end-nodes panes

  • Group ExpressionNodeData instances by EndNodeData; this is what the grids should display
  • Additional UI for navigating from instance to instance in the group
  • UI should cycle to last, then cycle to select all instances (multiselect tree), then select first instance

This will require multi-selection on treeview.

Undetermined error

When opening a certain expression in the visualizer, it returns a System.Exception.

Before calling FillPlaceholders, the expression looks like this:
beforefillplaceholder -- works
After, the left of the OrElse looks like this:
afterfillplaceholder -- left
and the right looks like this:
afterfillplaceholder -- right

This is the .ToString of the complete expression:

(LikeString(Param_0.Email, value(Machshevet.Core.Filtering+_Closure$__1-3).$VB$Local_phrase1, Text) OrElse LikeString(Param_0.Email, value(Machshevet.Core.Filtering+_Closure$__1-3).$VB$Local_kbtext1, Text))

and the DebugView:

.Call Microsoft.VisualBasic.CompilerServices.LikeOperator.LikeString(
    $var1.Email,
    .Constant<Machshevet.Core.Filtering+_Closure$__1-3>(Machshevet.Core.Filtering+_Closure$__1-3).$VB$Local_phrase1,
    .Constant<Microsoft.VisualBasic.CompareMethod>(Text)) || .Call Microsoft.VisualBasic.CompilerServices.LikeOperator.LikeString(
    $var1.Email,
    .Constant<Machshevet.Core.Filtering+_Closure$__1-3>(Machshevet.Core.Filtering+_Closure$__1-3).$VB$Local_kbtext1,
    .Constant<Microsoft.VisualBasic.CompareMethod>(Text))

Verify that nested closure classes work properly

I saw a compiler generated expression where the closure class instance was itself an instance of another closure class:

LambdaExpression
  - Body: MemberAccessExpression
      - Expression: MemberAccessExpression - <instance of closure class>
          - Constant: <instance of second closure class>

The code formatters have been fixed to treat members of an expression whose type is a closure classes as simple variables, even when the instance of said member is itself only the member of another closure class.

Nevertheless, I am unable to reproduce in tests, so I am leaving this open for now.

Render calls to String.Format as interpolated strings

When creating an expression with an interpolated string:

int i = 5;
Expression<Func<string>> expr = () => $"{i}";

the compiler generates the expression using a call to String.Format and a composite format string; in other words, like the following expression:

expr = () => string.Format("{0}", i);

Therefore, when rendering the expression in C# or VB.NET, it would be better to render such calls (to String.Format where the first parameter is a ConstantExpression containing a string) as interpolated strings.

List of types which can be visualized

Currently, the visualizer is only registered for Expression. Allow registering for other types used in expression trees:

Type Visualizer enabled
Expression Y
MemberBinding Y
CatchBlock
ElementInit Y
IArgumentProvider
IDynamicExpression
LabelTarget
SwitchCase

This will require another attribute call for each type, and that the VisualizerData constructor properly be able to handle each of these types take an object instead of a more specific type (until and if C# implements intersection types), taking an optional VisualizerDataOptions as well.

See also #41

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.