vscode-antlr4 icon indicating copy to clipboard operation
vscode-antlr4 copied to clipboard

Rendered ATN graph is a "mess"

Open mikecargal opened this issue 3 years ago • 6 comments

Not sure if I have something broken in my install, but the ATN graphs that are being rendered are pretty much a "mess"

for the following rule:

expr
    : '(' expr ')'                                   # ParenExpr
    | <assoc = right> base = expr '^' exp = expr     # ExpExpr
    | lhs = expr ('*' | '/') rhs = expr              # MulDivExpr
    | lhs = expr ('+' | '-') rhs = expr              # AddSubExpr
    | lhs = expr (LT | LE | EQ | GE | GT) rhs = expr # CompareExpr
    | NUMBER                                         # NumberExpr
    | TRUE                                           # BooleanExpr
    | FALSE                                          # FalseExpr
    | STRING                                         # StringExpr
    | ID                                             # IDExpr
    ;

This is what the ATN renders as (I also included the preview of the *.dot file for the same rule for reference)

Screen Shot 2021-05-24 at 3 54 22 PM

I can drag things around a bit to improve the rendering, but the orphaned node is a bit disconcerting (node "100" isn't even in the *.dot file):

digraph ATN {
rankdir=LR;
s9[fontsize=11, label="9", shape=doublecircle, fixedsize=true, width=.6];
s70[fontsize=11,label="70", shape=circle, fixedsize=true, width=.55, peripheries=1];
s71[fontsize=11,label="71", shape=circle, fixedsize=true, width=.55, peripheries=1];
s8[fontsize=11,label="8", shape=circle, fixedsize=true, width=.55, peripheries=1];
s72[fontsize=11,label="72", shape=circle, fixedsize=true, width=.55, peripheries=1];
s73[fontsize=11,label="73", shape=circle, fixedsize=true, width=.55, peripheries=1];
s74[fontsize=11,label="74", shape=circle, fixedsize=true, width=.55, peripheries=1];
s75[fontsize=11,label="75", shape=circle, fixedsize=true, width=.55, peripheries=1];
s76[fontsize=11,label="76", shape=circle, fixedsize=true, width=.55, peripheries=1];
s77[fontsize=11,label="77", shape=circle, fixedsize=true, width=.55, peripheries=1];
s78[fontsize=11,label="78", shape=circle, fixedsize=true, width=.55, peripheries=1];
s79[fontsize=11,label="79", shape=circle, fixedsize=true, width=.55, peripheries=1];
s80[fontsize=11,label="{&rarr;\n80\nd=8|{<p0>|<p1>|<p2>|<p3>|<p4>|<p5>}}", shape=record, fixedsize=false, peripheries=1];
s81[fontsize=11,label="&larr;\n81", shape=circle, fixedsize=true, width=.55, peripheries=1];
s82[fontsize=11,label="82", shape=circle, fixedsize=true, width=.55, peripheries=1];
s83[fontsize=11,label="83", shape=circle, fixedsize=true, width=.55, peripheries=1];
s84[fontsize=11,label="84", shape=circle, fixedsize=true, width=.55, peripheries=1];
s85[fontsize=11,label="85", shape=circle, fixedsize=true, width=.55, peripheries=1];
s86[fontsize=11,label="86", shape=circle, fixedsize=true, width=.55, peripheries=1];
s87[fontsize=11,label="87", shape=circle, fixedsize=true, width=.55, peripheries=1];
s88[fontsize=11,label="88", shape=circle, fixedsize=true, width=.55, peripheries=1];
s89[fontsize=11,label="89", shape=circle, fixedsize=true, width=.55, peripheries=1];
s90[fontsize=11,label="90", shape=circle, fixedsize=true, width=.55, peripheries=1];
s91[fontsize=11,label="91", shape=circle, fixedsize=true, width=.55, peripheries=1];
s92[fontsize=11,label="92", shape=circle, fixedsize=true, width=.55, peripheries=1];
s93[fontsize=11,label="93", shape=circle, fixedsize=true, width=.55, peripheries=1];
s94[fontsize=11,label="{&rarr;\n94*\nd=9|{<p0>|<p1>|<p2>|<p3>}}", shape=record, fixedsize=false, peripheries=1];
s95[fontsize=11,label="&larr;\n95", shape=circle, fixedsize=true, width=.55, peripheries=1];
s96[fontsize=11,label="{96*\nd=10|{<p0>|<p1>}}", shape=record, fixedsize=false, peripheries=1];
s97[fontsize=11,label="97", shape=circle, fixedsize=true, width=.55, peripheries=1];
s98[fontsize=11,label="98*", shape=circle, fixedsize=true, width=.55, peripheries=1];
s8 -> s80 [fontname="Times-Italic", label="&epsilon;"];
s80:p0 -> s70 [fontname="Times-Italic", label="&epsilon;"];
s80:p1 -> s75 [fontname="Times-Italic", label="&epsilon;"];
s80:p2 -> s76 [fontname="Times-Italic", label="&epsilon;"];
s80:p3 -> s77 [fontname="Times-Italic", label="&epsilon;"];
s80:p4 -> s78 [fontname="Times-Italic", label="&epsilon;"];
s80:p5 -> s79 [fontname="Times-Italic", label="&epsilon;"];
s70 -> s71 [fontsize=11, fontname="Courier", arrowsize=.7, label = "action_4:-1", arrowhead = normal];
s75 -> s81 [fontsize=11, fontname="Courier", arrowsize=.7, label = "NUMBER", arrowhead = normal];
s76 -> s81 [fontsize=11, fontname="Courier", arrowsize=.7, label = "'true'", arrowhead = normal];
s77 -> s81 [fontsize=11, fontname="Courier", arrowsize=.7, label = "'false'", arrowhead = normal];
s78 -> s81 [fontsize=11, fontname="Courier", arrowsize=.7, label = "STRING", arrowhead = normal];
s79 -> s81 [fontsize=11, fontname="Courier", arrowsize=.7, label = "ID", arrowhead = normal];
s71 -> s72 [fontsize=11, fontname="Courier", arrowsize=.7, label = "'('", arrowhead = normal];
s81 -> s96 [fontname="Times-Italic", label="&epsilon;"];
s72 -> s73 [fontsize=11, fontname="Courier", arrowsize=.7, label = "<expr[0]>", arrowhead = normal];
s96:p0 -> s94 [fontname="Times-Italic", label="&epsilon;"];
s96:p1 -> s97 [fontname="Times-Italic", label="&epsilon;"];
s73 -> s74 [fontsize=11, fontname="Courier", arrowsize=.7, label = "')'", arrowhead = normal];
s94:p0 -> s82 [fontname="Times-Italic", label="&epsilon;"];
s94:p1 -> s85 [fontname="Times-Italic", label="&epsilon;"];
s94:p2 -> s88 [fontname="Times-Italic", label="&epsilon;"];
s94:p3 -> s91 [fontname="Times-Italic", label="&epsilon;"];
s97 -> s9 [fontname="Times-Italic", label="&epsilon;"];
s74 -> s81 [fontname="Times-Italic", label="&epsilon;"];
s82 -> s83 [fontsize=11, fontname="Courier", arrowsize=.7, label = "9 >= _p", arrowhead = normal];
s85 -> s86 [fontsize=11, fontname="Courier", arrowsize=.7, label = "8 >= _p", arrowhead = normal];
s88 -> s89 [fontsize=11, fontname="Courier", arrowsize=.7, label = "7 >= _p", arrowhead = normal];
s91 -> s92 [fontsize=11, fontname="Courier", arrowsize=.7, label = "6 >= _p", arrowhead = normal];
s83 -> s84 [fontsize=11, fontname="Courier", arrowsize=.7, label = "'^'", arrowhead = normal];
s86 -> s87 [fontsize=11, fontname="Courier", arrowsize=.7, label = "{'*', '/'}", arrowhead = normal];
s89 -> s90 [fontsize=11, fontname="Courier", arrowsize=.7, label = "{'+', '-'}", arrowhead = normal];
s92 -> s93 [fontsize=11, fontname="Courier", arrowsize=.7, label = "{'==', '<', '<=', '>', '>='}", arrowhead = normal];
s84 -> s95 [fontsize=11, fontname="Courier", arrowsize=.7, label = "<expr[9]>", arrowhead = normal];
s87 -> s95 [fontsize=11, fontname="Courier", arrowsize=.7, label = "<expr[9]>", arrowhead = normal];
s90 -> s95 [fontsize=11, fontname="Courier", arrowsize=.7, label = "<expr[8]>", arrowhead = normal];
s93 -> s95 [fontsize=11, fontname="Courier", arrowsize=.7, label = "<expr[7]>", arrowhead = normal];
s95 -> s98 [fontname="Times-Italic", label="&epsilon;"];
s98 -> s96 [fontname="Times-Italic", label="&epsilon;", style="dashed"];
}

If it should be rendering fine for averyone else, would appreciate any tips as to what I may have done to my environment.

mikecargal avatar May 24 '21 20:05 mikecargal

For reference, I was able to use the *.dot preview to pull things around to a decent rendering. (I had to go chasing down the poor "node 100" that took off wandering off screen (lol))

Screen Shot 2021-05-24 at 4 10 08 PM

Other than the mysterious node 100, it seems to match up with the *.dot preview.

mikecargal avatar May 24 '21 20:05 mikecargal

It's not a bug, but a feature :-) What you see is all that D3.js can come up with. I'm not aware of any D3.js layouter which would produce a graph like the DOT render does. The node positions are compute based on a force-directed method, which is, admittedly, not very useful for the kind of graph we want for ATN display. I'm open to use a different layout if someone would lead me to a better approach.

The isolated node is a bit weird, yes. I don't know for sure where it comes from, but I think it's one of the nodes that the TS runtime optimized out of the normal ATN. It does neither have incoming nor outgoing connections. The only reason for showing it is that it is still in the ATN states list, which I use to get all nodes for a particular rule. I could ignore it (maybe I should add a setting for that), but I wanted to have it shown to help investigating at some point what exactly is going on. But it never had enough priority so far, to warrant the extra effort.

mike-lischke avatar May 25 '21 06:05 mike-lischke

Yeah, I could tell that it was acting like a force directed graph. Like you say, the result isn’t really helpful. I’m aware of, but not familiar with d3.JS. Thought I’d pass it along because the examples look cleaner (and I thought I’d seen them arranged more cleaning in the past) and thought maybe there’d been a regression. If I find time, I may look around a bit (oddly, retirement is not providing nearly the surplus of time I expected. I do like the plugin, so thanks for the work you’ve done.

mikecargal avatar May 25 '21 11:05 mikecargal

I manually adjusted all graphs I posted anywhere (Stackoverflow, documentation, webpages etc.). However, the display has always been like this (and is pretty slow with many nodes). I plan for a long time to improve it to something like the DOT output, but haven't had the opportunity to do so. Which means it will stay like that until either someone opens a PR with a better implementation or at least points me to a lib or similar which allows to change the rendering.

mike-lischke avatar May 26 '21 15:05 mike-lischke

Coincidentally, I was sitting on a Strumenta community call today and Federico was using a JavaScript tool for processing dot files. I caught a glimpse that hinted at the tool and tracked it to this... https://github.com/magjac/d3-graphviz. (the graphviz and d3 references reminded me, for some reason :), of this topic, so I thought I'd pass it along.)

I haven't looked in detail, but plan to look at it a bit further. (It'll be some time before I find time to attempt a change/PR (would have to come up to speed on VS-Code plugins as part of the process.). I thought I'd pass along the information though.

mikecargal avatar May 27 '21 17:05 mikecargal

That's a pretty cool lib. I hadn't heard about that before. And even more interesting is the wasm foundation for graphviz. Definitely worth to take a look or two. Thanks for the pointer!

mike-lischke avatar May 27 '21 17:05 mike-lischke

I'm afraid this won't happen any time soon, so I'm closing this issue. If someone wants to take a stab at this - I'm happy to accept pull requests.

mike-lischke avatar Nov 09 '23 21:11 mike-lischke