Skip to content

Quasy quoting for assists #2227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
matklad opened this issue Nov 13, 2019 · 7 comments
Open

Quasy quoting for assists #2227

matklad opened this issue Nov 13, 2019 · 7 comments
Labels
A-assists Broken Window Bugs / technical debt to be addressed immediately E-hard fun A technically challenging issue with high impact S-actionable Someone could pick this issue up and work on it right now

Comments

@matklad
Copy link
Member

matklad commented Nov 13, 2019

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 matklad added E-hard fun A technically challenging issue with high impact labels Nov 13, 2019
@matklad
Copy link
Member Author

matklad commented Nov 13, 2019

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.

@Veykril
Copy link
Member

Veykril commented Nov 3, 2020

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?

@matklad
Copy link
Member Author

matklad commented Nov 3, 2020

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

@Veykril
Copy link
Member

Veykril commented Nov 4, 2020

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.

@lnicola lnicola added the S-actionable Someone could pick this issue up and work on it right now label Jan 25, 2021
@Veykril Veykril added A-assists Broken Window Bugs / technical debt to be addressed immediately labels Oct 4, 2023
@DropDemBits
Copy link
Contributor

DropDemBits commented Feb 16, 2024

  • 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 #779 (comment))

@Veykril
Copy link
Member

Veykril commented Feb 16, 2024

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.

@DropDemBits
Copy link
Contributor

Should we have separate quasi-quoting macros for the different parsing entry points (e.g. ty, expr, pattern, item, stmt)? Not sure if that would be needed as you could generate a tree for a higher-level syntax construct and grab the specific AST node you need, though it'd also be nice to not have to dig for the node.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-assists Broken Window Bugs / technical debt to be addressed immediately E-hard fun A technically challenging issue with high impact S-actionable Someone could pick this issue up and work on it right now
Projects
None yet
Development

No branches or pull requests

4 participants