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

Advanced queries via Go code #32

@mvdan

Description

@mvdan

Simple queries can be done as a pipeline, such as finding all unnecessary uses of [:] on strings:

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

However, this quickly breaks down if any non-linear logic is required. For example, what if we wanted to catch all unnecessary uses of [:], including both strings and slices? You might imagine a more complex syntax and language, like:

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

However, this would still be a limited subset of all the logic that you might want in your query. Another common example is variations on -g, such as contains at least 2 of X pattern, as opposed to contains at least 1 of X pattern.

Instead of complicating the query language further, we should leverage the Go language, which all gogrep users should already be familiar with. Our unnecessary [:] example above could be something like:

stmts := gogrep.FindAll(input, `$x[:]`)
stmts = gogrep.Filter(stmts, gogrep.AnyOf(
        gogrep.Type("string"),
        gogrep.Kind("slice"),
))
gogrep.Output(stmts, "should drop [:] on strings and slices")

All the features that are available via the command line would be available via this API, as the command line would be implemented using the API after all. For example, to make the code perform a rewrite instead of giving a warning, we could have:

stmts := gogrep.FindAll(input, `$x[:]`)
stmts = gogrep.Filter(stmts, gogrep.AnyOf(
        gogrep.Type("string"),
        gogrep.Kind("slice"),
))
stmts = gogrep.Substitute(stmts, "$x")
gogrep.WriteBack(stmts)

One of the important features of using Go code is the ability to compose commands in more interesting ways, such as our use of gogrep.AnyOf above. But it would also be possible to perform changes and filters directly, as one can range over the stmts list of type []ast.Stmt.

We could even add ways to simplify the writing of simpler pipe-like queries in Go code, such as:

gogrep.Pipe(input,
    gogrep.FindAll("$x[:]"),
    gogrep.Filter(gogrep.AnyOf(gogrep.Type("string"), gogrep.Kind("slice"))),
    gogrep.Substitute("$x"),
    gogrep.WriteBack,
)

The first step is to move the logic out of the main package, so that it can be imported as a Go package. I would also like to come up with a package name that is shorter than gogrep, as one will have to write it everywhere (assuming dot-imports are to be avoided). Perhaps gg for its initials, or gr for "grep".

/cc @rogpeppe @kytrinyx @quasilyte

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions