rust-analyzer icon indicating copy to clipboard operation
rust-analyzer copied to clipboard

Quasy quoting for assists

Open matklad opened this issue 6 years ago • 7 comments

Assist (and, once we have more of those, fixits and refactorings) need to produce a lot of syntax trees.

This is done with the help of make module at the moment. Here's how a moderately-complex let statement is produced:

let match_expr = {
    let happy_arm = make::match_arm(
        once(
            make::tuple_struct_pat(
                path,
                once(make::bind_pat(make::name("it")).into()),
            )
            .into(),
        ),
        make::expr_path(make::path_from_name_ref(make::name_ref("it"))).into(),
    );

    let sad_arm = make::match_arm(
        once(make::placeholder_pat().into()),
        early_expression.into(),
    );

    make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
};

let let_stmt = make::let_stmt(
    make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
    Some(match_expr.into()),
);

It would be sweet if the above code could be condensed to the following:

let let_stmt = magic! {
    let $bound_ident = match $cond_expr {
        $path(it) => it,
        _ => $early_expression,
    }
};

There exists a trivial solution: use format!, produce a string, re-parse string back into an AST. This actually works great! This is the solution employed by IntelliJ Rust(example), and I don't remember having any problems with it.

However, adding more type-safety seems like a good thing to try! So, the magic! macro should ideally produce the code above, and not some formatting-based thing.

matklad avatar Nov 13 '19 09:11 matklad

Random thoughts:

  • handing of whitespace is a known unknown
  • if we fail at fully type-safe solution, we might resort to a build string & reparse solution, with an additional runtime check that each interpolated value preserves it's kind after a reparse.

matklad avatar Nov 13 '19 09:11 matklad

I brainstormed a bit about this a week ago whether it would be possible to do this with macros-by-example, but I believe due to the nature of this trying to parse a tree as well as emitting a tree-ish expression this won't be possible to model with such a macro. How is RAs stance in regards to containing proc-macros as with such it should be fairly simple to implement I think?

Veykril avatar Nov 03 '20 22:11 Veykril

I think we should start adding some proc macros, if only to nudge ourselves into supporting them better. Not entirely sure that this will be simple to implement though, but it’s definitelly is worth trying

matklad avatar Nov 03 '20 23:11 matklad

Not entirely sure that this will be simple to implement though

Ye my choice of words was a bit unfortunate, I did not intend to say it would be easy to do.

I'll try exploring this sometime.

Veykril avatar Nov 04 '20 08:11 Veykril

  • handing of whitespace is a known unknown

Whitespace handling could probably be done using an autoformatter, or more reasonably using an autoindenter plus having the make constructors include the necessary whitespace and newline bits

  • if we fail at fully type-safe solution, we might resort to a build string & reparse solution, with an additional runtime check that each interpolated value preserves it's kind after a reparse.

It'd be nice to not have to resort to the stringify & reparse solution for the sake of tracking nodes easily, but that's probably my experience with the structured snippet API talking (which relies on being able to find nodes in the final post-edit tree) 😅

On an unrelated note, I was curious if the make constructors could be generated (or mostly generated) from the rust.ungrammar file? I'm not 100% sure about the feasibility of this idea though, and it may just be easier to add make constructors as we incrementally cover more and more syntax.

Edit: I see I'm not the first to think about that idea (see https://github.com/rust-lang/rust-analyzer/issues/779#issuecomment-462184072)

DropDemBits avatar Feb 16 '24 06:02 DropDemBits

The make api should be autogenerated yes, I've been meaning to touch upon that part soonish as i have a similar set up for a toy language now. Having our own formatter is also something we want still, its just also not implemented yet.

Veykril avatar Feb 16 '24 08:02 Veykril