Hello World

2020-04-22

While staring at the keywords section in the standard library, I had a sort of epiphany: how difficult would it be to create an interactive tool to explore Rust's syntax? Wouldn't it be nice if we could help with all those pesky keywords and punctuation symbols while exploring real code?

~100h and ~3000LOC later, I'm neck deep into explaine.rs. Getting the punctuation and the keywords was easy, but things quickly spiraled out of control. Since we're on it, we could provide some contextual info, right? Right. Only the problem domain has expanded significantly and now I'm hacking together a sorta-compiler-frontend. Since we're on it, we could try to explore all the dark corners of Rust syntax, right? Ouch. I don't even know if it · will · ever · be · done.

The UI itself is somewhat interesting. The "analyzer" is just an implementation of syn's visitor, compiled to WebAssembly. The playground then runs it from a Web Worker, to avoid blocking the main thread. As an extra optimization, we also try to pre-compute "in the background" all possible "hitboxes" in the code where a click would find some help, so we can render a hover effect on top of them efficiently. This pre-computation is unoptimized to the point of embarrassment though.

The approach for the "analysis" is quite blunt. It traverses the syntax tree following the branch that contains the cursor position. At some point we either find a leaf we have something to say about, or on the way back up we have some fallback. For instance, if you select something uninteresting within a closure's body, it highlights the whole closure. This method is rather fragile and there's a ton of corner cases that have to be handled manually. For instance, a mut pattern has a general description:

match x {
  // "The `x` binding this pattern introduces is mutable..."
  Some(mut x) => {},
  _ => {}
}

But there are a few places where bindings can be introduced that are "special", which merit a more elaborated response:

// A `let mut` statement that introduces the _mutable_ local variable `x`...
let mut x;

I don't know much about ASTs and syntax analysis (it shows), so I suspect there's probably a better way of doing this. rustc or rust-analyzer lower the AST to some intermediate representation that might be more amenable to be inspected. However (a) that sounds like a lot of work (b) it is somehow working anyway, and more seriously (c) I worry that a more sophisticated approach could incur in code bloat, which is very undesirable for something that has to run on the web (And that it has to feel relatively light. I think rust-analyzer is close to being runnable on the web, but that's a much more heavyweight beast).

Fun times.

_rvidal🐦 · gh