vscode-antlr4
vscode-antlr4 copied to clipboard
Rendered ATN graph is a "mess"
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](https://user-images.githubusercontent.com/2240827/119400829-b14be200-bca8-11eb-917f-565d4796d372.png)
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="{→\n80\nd=8|{<p0>|<p1>|<p2>|<p3>|<p4>|<p5>}}", shape=record, fixedsize=false, peripheries=1];
s81[fontsize=11,label="←\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="{→\n94*\nd=9|{<p0>|<p1>|<p2>|<p3>}}", shape=record, fixedsize=false, peripheries=1];
s95[fontsize=11,label="←\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="ε"];
s80:p0 -> s70 [fontname="Times-Italic", label="ε"];
s80:p1 -> s75 [fontname="Times-Italic", label="ε"];
s80:p2 -> s76 [fontname="Times-Italic", label="ε"];
s80:p3 -> s77 [fontname="Times-Italic", label="ε"];
s80:p4 -> s78 [fontname="Times-Italic", label="ε"];
s80:p5 -> s79 [fontname="Times-Italic", label="ε"];
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="ε"];
s72 -> s73 [fontsize=11, fontname="Courier", arrowsize=.7, label = "<expr[0]>", arrowhead = normal];
s96:p0 -> s94 [fontname="Times-Italic", label="ε"];
s96:p1 -> s97 [fontname="Times-Italic", label="ε"];
s73 -> s74 [fontsize=11, fontname="Courier", arrowsize=.7, label = "')'", arrowhead = normal];
s94:p0 -> s82 [fontname="Times-Italic", label="ε"];
s94:p1 -> s85 [fontname="Times-Italic", label="ε"];
s94:p2 -> s88 [fontname="Times-Italic", label="ε"];
s94:p3 -> s91 [fontname="Times-Italic", label="ε"];
s97 -> s9 [fontname="Times-Italic", label="ε"];
s74 -> s81 [fontname="Times-Italic", label="ε"];
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="ε"];
s98 -> s96 [fontname="Times-Italic", label="ε", 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.
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](https://user-images.githubusercontent.com/2240827/119402161-8a8eab00-bcaa-11eb-9cd0-a237dffb221a.png)
Other than the mysterious node 100, it seems to match up with the *.dot preview.
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.
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.
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.
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.
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!
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.