Skip to content
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

is there a way to repeat elements in patterns #16

Open
symphorien opened this issue Feb 11, 2023 · 4 comments
Open

is there a way to repeat elements in patterns #16

symphorien opened this issue Feb 11, 2023 · 4 comments

Comments

@symphorien
Copy link

Hello, is there a way to write a pattern that transforms [ f(1), f(2), .... any number of f(integer) ] into map(f, [ 1, 2, any number of integers ]) ?

If I understand correctly tree sitter queries support wildcards such as *.

@cshuaimin
Copy link
Owner

cshuaimin commented Feb 26, 2023

It will be a good improvement to add this! And the implementation should be trivial as treesitter already has repetitions.

However I don't have a good design for the syntax yet.

  • [ f($a), ...], i.e. use ... to repeat same level node?
  • [ $(f($a))+ ], i.e. Rust declarative macro like syntax?
  • ast-grep uses $$$

@symphorien
Copy link
Author

I think the rust macro syntax is nice because it also solves the problem of the syntax of the replacement part.

@cshuaimin
Copy link
Owner

Rust declarative macro syntax is great, however there's too many $ and parens. It's hard to add repetition to a normal pattern, because you need to surround some structure with $().

I'v came up with following design and I plan to implement this feature after multi-file search.

Syntax

  • use $.. in the pattern or replacement to indicate a repetition (... is commonly used in programming languages.)
  • the exact meaning of $.. is: repeat the structure of previous same level sub-trees (previous sibling)
  • $.. is not required to be used in the same level in pattern and replacement, this is useful to use some repetition in another place
  • example 1: [ f($a), $..] ==>> map(f, [ $a, $.. ])
  • example 2: { $k: $v, $.. } ==>> { $v: $k, $.. }, the same level sub-tree of $.. is $k: $v pair, and the first $.. means "search more pairs of arbitary key and value", and the second $.. means "generate the same number of pairs as in the pattern, replacing any wildcards"

Separators

Separators are important when it comes to repetition. They'll be any non-named nodes between previous sibling and the $.. wildcard.

  • $.. will be removed before parsing the pattern, while normal $name wildcard will be replaced to an identifier. Because replacing $.. to an identifier may results in invalid syntax. e.g. in let a = 1; $.. every line needs to be terminated with ;, and previous json example.
  • the previous sibling is calcluated by finding largest node which ends with the position of $..

In [ $a, $..], the separator is , (comma and space), in

fn f() {
    let a = 1;
    $..
}

the separartor is \n (newline and indent). Note that ; is part of the let declaration node, not a individual node.

These separators will chain every instance of repetition nicely and the output of ssr will be well formatted.

More examples

Rust vec![] macro:

vec![$a, $..]
==>>
{
    let mut temp_vec = Vec::new();
    temp_vec.push($a);
    $..
    temp_vec
}

Convert import { a, b } from 'lib' to

import A from 'lib/a'
import B from 'lib/b'
import { $a, $.. } from '$lib';
==>>
import $a from '$lib/$a';
$..

@symphorien
Copy link
Author

nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants