Skip to content
This repository has been archived by the owner on Jun 9, 2021. It is now read-only.

Add type predicates support #31

Closed
quasilyte opened this issue Apr 29, 2018 · 5 comments
Closed

Add type predicates support #31

quasilyte opened this issue Apr 29, 2018 · 5 comments

Comments

@quasilyte
Copy link
Contributor

quasilyte commented Apr 29, 2018

It would be useful to search for $x of type that have a type that satisfies some predicate.

For example, I would like to grep for slices with elements of type $T.
More precisely, I wanted to find all slicing expressions of form s[:] where s is a string or slice.

$ gogrep '$(s type(string))[:]' std
strings/replace.go:450:22: s[:]

This works, but I need to manually substitute string with all other types I want to check.

With type predicates, it would be possible to describe function that accepts node that is being matched with some kind of context object (that includes types info) and returns bool.

I have no idea about how to enable user-defined predicates.
(Go plugins doesn't seem first class citizen.)

@mvdan
Copy link
Owner

mvdan commented Apr 29, 2018

Thanks for the suggestion - indeed, completely custom logic isn't supported at the moment.

But you can do most of what you're after in two queries with the current program, I believe. At the moment, there are four type filters you can apply - type, asgn, conv, and is. The first checks for the exact type, the second for being assignable to a type, the third for being convertible to a type, and the last for having an underlying type kind.

So, in your case, these two queries should do it:

$ gogrep '$(s type(string))[:]' std
$ gogrep '$(s is(slice))[:]' std

I ran the second and looked at some of the results, and it seems correct.

I realise this is all poorly documented (you're going to have to look at match_test.go for examples, for now). The big reason is that this type stuff was one of the latest additions, and I want to refactor it - see #28. I'll document all of this properly once the refactor is done. I plan to spend at least a few days on this tool in the coming week or two.

@mvdan
Copy link
Owner

mvdan commented Apr 29, 2018

Going back to custom logic - I had some ideas to add a bit more flexibility, like #26. But I think what I'll instead allow is using gogrep as a library.

Then, you'd write a twenty line Go file, which would import gogrep and use it, and which would define its own logic. Think of it like writing a linter, but having to write much less code and having high-level funcs like find all nodes matching this pattern, or go to the node's parent. You'd also not have to worry about the usual boilerplate that comes with writing a linter, such as handling arguments, loading programs, writing the output matches, etc.

However, I need to think really hard about what that API would look like, and what those twenty-line Go programs would look like.

@quasilyte
Copy link
Contributor Author

quasilyte commented Apr 29, 2018

@mvdan, thank you. That's helpful.

gogrep is a good tool, nice to hear it's still being maintained.

About API.
I tried to do some kind of Go AST matching patterns as a library.
It was very regexp-like: Compile-like function to build matcher and different Match methods on that pattern.
Pattern was permitted to have named capture groups that are populated after each Match invocation.
As for custom filters, every match caused user callback to be called, so the final decision about match is done with user custom matcher (default callback always returns true).
The library itself had weird S-expr like syntax, this is why gogrep is better: it uses Go syntax to match Go. (pattern example, and public API)

@mvdan
Copy link
Owner

mvdan commented May 10, 2018

Apologies for the silence - I have been working on a refactor for weeks, which I have finally finished just now. It was mostly thinking about what design I'll want to have in the long run.

I still think custom logic should be done via Go code. I've closed #26, and will work on that soon.

As for your example above, I still think that what I gave you is the best that the command line tool should do. If we try to add certain logic into this pipe-like command line tool, such as logical ORs, it's quickly going to become complex. Whereas that logic will be very easy in Go code.

After the refactor, here are your new queries:

$ gogrep -x '$x[:]' -a 'type(string)' std
$ gogrep -x '$x[:]' -a 'is(slice)' std

I'm going to continue the work towards the goal above in the next few weeks. So I'd say this is not the best time to contribute, as the code will rapidly change. However, if you use the tool and find bugs or have ideas for features, please do bring them up :)

I also didn't know you had written something similar! Glad to have your input on all this, and it's good that you think this design is decent :)

@mvdan
Copy link
Owner

mvdan commented May 10, 2018

Assuming that this issue was just about checking types, I think it can be closed. We can continue the discussion on advanced queries and custom logic in #32.

@mvdan mvdan closed this as completed May 10, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants