aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/quasilyte/gogrep
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2022-09-05 14:27:54 +0200
committerGitHub <noreply@github.com>2022-09-05 12:27:54 +0000
commitb2f2446b46bf02821d90ebedadae2bf7ae0e880e (patch)
tree923cf42842918d6bebca1d6bbdc08abed54d274d /vendor/github.com/quasilyte/gogrep
parente6654faff4bcca4be92e9a8596fd4b77f747c39e (diff)
go.mod, vendor: update (#3358)
* go.mod, vendor: remove unnecessary dependencies Commands: 1. go mod tidy 2. go mod vendor * go.mod, vendor: update cloud.google.com/go Commands: 1. go get -u cloud.google.com/go 2. go mod tidy 3. go mod vendor * go.mod, vendor: update cloud.google.com/* Commands: 1. go get -u cloud.google.com/storage cloud.google.com/logging 2. go mod tidy 3. go mod vendor * go.mod, .golangci.yml, vendor: update *lint* Commands: 1. go get -u golang.org/x/tools github.com/golangci/golangci-lint@v1.47.0 2. go mod tidy 3. go mod vendor 4. edit .golangci.yml to suppress new errors (resolved in the same PR later) * all: fix lint errors hash.go: copy() recommended by gosimple parse.go: ent is never nil verifier.go: signal.Notify() with unbuffered channel is bad. Have no idea why. * .golangci.yml: adjust godot rules check-all is deprecated, but still work if you're hesitating too - I'll remove this commit
Diffstat (limited to 'vendor/github.com/quasilyte/gogrep')
-rw-r--r--vendor/github.com/quasilyte/gogrep/.gitignore4
-rw-r--r--vendor/github.com/quasilyte/gogrep/.golangci.yml49
-rw-r--r--vendor/github.com/quasilyte/gogrep/LICENSE33
-rw-r--r--vendor/github.com/quasilyte/gogrep/Makefile19
-rw-r--r--vendor/github.com/quasilyte/gogrep/README.md41
-rw-r--r--vendor/github.com/quasilyte/gogrep/compile.go1174
-rw-r--r--vendor/github.com/quasilyte/gogrep/compile_import.go57
-rw-r--r--vendor/github.com/quasilyte/gogrep/gen_operations.go357
-rw-r--r--vendor/github.com/quasilyte/gogrep/go.mod8
-rw-r--r--vendor/github.com/quasilyte/gogrep/go.sum8
-rw-r--r--vendor/github.com/quasilyte/gogrep/gogrep.go180
-rw-r--r--vendor/github.com/quasilyte/gogrep/instructions.go116
-rw-r--r--vendor/github.com/quasilyte/gogrep/internal/stdinfo/stdinfo.go151
-rw-r--r--vendor/github.com/quasilyte/gogrep/match.go937
-rw-r--r--vendor/github.com/quasilyte/gogrep/nodetag/nodetag.go280
-rw-r--r--vendor/github.com/quasilyte/gogrep/operation_string.go146
-rw-r--r--vendor/github.com/quasilyte/gogrep/operations.gen.go1570
-rw-r--r--vendor/github.com/quasilyte/gogrep/parse.go397
-rw-r--r--vendor/github.com/quasilyte/gogrep/slices.go58
19 files changed, 5585 insertions, 0 deletions
diff --git a/vendor/github.com/quasilyte/gogrep/.gitignore b/vendor/github.com/quasilyte/gogrep/.gitignore
new file mode 100644
index 000000000..ec560f1c9
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/.gitignore
@@ -0,0 +1,4 @@
+.idea
+.vscode
+coverage.txt
+bin
diff --git a/vendor/github.com/quasilyte/gogrep/.golangci.yml b/vendor/github.com/quasilyte/gogrep/.golangci.yml
new file mode 100644
index 000000000..16d03c54d
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/.golangci.yml
@@ -0,0 +1,49 @@
+{
+ "run": {
+ # timeout for analysis, e.g. 30s, 5m, default is 1m
+ "deadline": "3m",
+ },
+ "fast": false,
+ "linters": {
+ "enable": [
+ "deadcode",
+ "errcheck",
+ "gas",
+ "gocritic",
+ "gofmt",
+ "goimports",
+ "revive",
+ "govet",
+ "gosimple",
+ "ineffassign",
+ "megacheck",
+ "misspell",
+ "nakedret",
+ "staticcheck",
+ "structcheck",
+ "typecheck",
+ "unconvert",
+ "unused",
+ "varcheck",
+ ],
+ },
+ "disable": [
+ "depguard",
+ "dupl",
+ "gocyclo",
+ "interfacer",
+ "lll",
+ "maligned",
+ "prealloc",
+ ],
+ "linters-settings": {
+ "gocritic": {
+ "enabled-tags": [
+ "style",
+ "diagnostic",
+ "performance",
+ "experimental",
+ ],
+ },
+ },
+}
diff --git a/vendor/github.com/quasilyte/gogrep/LICENSE b/vendor/github.com/quasilyte/gogrep/LICENSE
new file mode 100644
index 000000000..575b56ae1
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/LICENSE
@@ -0,0 +1,33 @@
+BSD 3-Clause License
+
+Copyright (c) 2021, Iskander (Alex) Sharipov
+
+Originally based on the Daniel Martí code | Copyright (c) 2017, Daniel Martí. All rights reserved.
+See https://github.com/mvdan/gogrep
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/quasilyte/gogrep/Makefile b/vendor/github.com/quasilyte/gogrep/Makefile
new file mode 100644
index 000000000..d05331f42
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/Makefile
@@ -0,0 +1,19 @@
+GOPATH_DIR=`go env GOPATH`
+
+test:
+ go test -count 2 -coverpkg=./... -coverprofile=coverage.txt -covermode=atomic ./...
+ go test -bench=. ./...
+ @echo "everything is OK"
+
+ci-lint:
+ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH_DIR)/bin v1.43.0
+ $(GOPATH_DIR)/bin/golangci-lint run ./...
+ go install github.com/quasilyte/go-consistent@latest
+ $(GOPATH_DIR)/bin/go-consistent . ./internal/... ./nodetag/... ./filters/...
+ @echo "everything is OK"
+
+lint:
+ golangci-lint run ./...
+ @echo "everything is OK"
+
+.PHONY: ci-lint lint test
diff --git a/vendor/github.com/quasilyte/gogrep/README.md b/vendor/github.com/quasilyte/gogrep/README.md
new file mode 100644
index 000000000..b6c2c47c1
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/README.md
@@ -0,0 +1,41 @@
+![logo](https://github.com/quasilyte/vscode-gogrep/blob/master/docs/logo.png?raw=true)
+
+![Build Status](https://github.com/quasilyte/gogrep/workflows/Go/badge.svg)
+[![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/quasilyte/gogrep)](https://pkg.go.dev/github.com/quasilyte/gogrep)
+[![Go Report Card](https://goreportcard.com/badge/github.com/quasilyte/gogrep)](https://goreportcard.com/report/github.com/quasilyte/gogrep)
+![Code Coverage](https://codecov.io/gh/quasilyte/gogrep/branch/master/graph/badge.svg)
+
+# gogrep
+
+This is an attempt to move a modified [gogrep](https://github.com/mvdan/gogrep) from the [go-ruleguard](https://github.com/quasilyte/go-ruleguard) project, so it can be used independently.
+
+This repository contains two Go modules. One for the gogrep library and the second one for the command-line tool.
+
+## gogrep as a library
+
+To get a gogrep library module, install the root Go module.
+
+```bash
+$ go get github.com/quasilyte/gogrep
+```
+
+## gogrep as a command-line utility
+
+To get a gogrep command-line tool, install the `cmd/gogrep` Go submodule.
+
+```bash
+$ go install github.com/quasilyte/cmd/gogrep
+```
+
+See [docs/gogrep_cli.md](_docs/gogrep_cli.md) to learn how to use it.
+
+## Used by
+
+A gogrep library is used by:
+
+* [go-ruleguard](https://github.com/quasilyte/go-ruleguard)
+* [gocorpus](https://github.com/quasilyte/gocorpus)
+
+## Acknowledgements
+
+The original gogrep is written by the [Daniel Martí](https://github.com/mvdan).
diff --git a/vendor/github.com/quasilyte/gogrep/compile.go b/vendor/github.com/quasilyte/gogrep/compile.go
new file mode 100644
index 000000000..cc60c05a6
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/compile.go
@@ -0,0 +1,1174 @@
+package gogrep
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ "github.com/quasilyte/gogrep/internal/stdinfo"
+)
+
+type compileError string
+
+func (e compileError) Error() string { return string(e) }
+
+type compiler struct {
+ config CompileConfig
+
+ prog *program
+ stringIndexes map[string]uint8
+ ifaceIndexes map[interface{}]uint8
+
+ info *PatternInfo
+
+ insideStmtList bool
+}
+
+func (c *compiler) Compile(root ast.Node, info *PatternInfo) (p *program, err error) {
+ defer func() {
+ if err != nil {
+ return
+ }
+ rv := recover()
+ if rv == nil {
+ return
+ }
+ if parseErr, ok := rv.(compileError); ok {
+ err = parseErr
+ return
+ }
+ panic(rv) // Not our panic
+ }()
+
+ c.info = info
+ c.prog = &program{
+ insts: make([]instruction, 0, 8),
+ }
+ c.stringIndexes = make(map[string]uint8)
+ c.ifaceIndexes = make(map[interface{}]uint8)
+
+ c.compileNode(root)
+
+ if len(c.prog.insts) == 0 {
+ return nil, c.errorf(root, "0 instructions generated")
+ }
+
+ return c.prog, nil
+}
+
+func (c *compiler) errorf(n ast.Node, format string, args ...interface{}) compileError {
+ loc := c.config.Fset.Position(n.Pos())
+ message := fmt.Sprintf("%s:%d: %s", loc.Filename, loc.Line, fmt.Sprintf(format, args...))
+ return compileError(message)
+}
+
+func (c *compiler) toUint8(n ast.Node, v int) uint8 {
+ if !fitsUint8(v) {
+ panic(c.errorf(n, "implementation error: %v can't be converted to uint8", v))
+ }
+ return uint8(v)
+}
+
+func (c *compiler) internVar(n ast.Node, s string) uint8 {
+ c.info.Vars[s] = struct{}{}
+ index := c.internString(n, s)
+ return index
+}
+
+func (c *compiler) internString(n ast.Node, s string) uint8 {
+ if index, ok := c.stringIndexes[s]; ok {
+ return index
+ }
+ index := len(c.prog.strings)
+ if !fitsUint8(index) {
+ panic(c.errorf(n, "implementation limitation: too many string values"))
+ }
+ c.stringIndexes[s] = uint8(index)
+ c.prog.strings = append(c.prog.strings, s)
+ return uint8(index)
+}
+
+func (c *compiler) internIface(n ast.Node, v interface{}) uint8 {
+ if index, ok := c.ifaceIndexes[v]; ok {
+ return index
+ }
+ index := len(c.prog.ifaces)
+ if !fitsUint8(index) {
+ panic(c.errorf(n, "implementation limitation: too many values"))
+ }
+ c.ifaceIndexes[v] = uint8(index)
+ c.prog.ifaces = append(c.prog.ifaces, v)
+ return uint8(index)
+}
+
+func (c *compiler) emitInst(inst instruction) {
+ c.prog.insts = append(c.prog.insts, inst)
+}
+
+func (c *compiler) emitInstOp(op operation) {
+ c.emitInst(instruction{op: op})
+}
+
+func (c *compiler) compileNode(n ast.Node) {
+ switch n := n.(type) {
+ case *ast.File:
+ c.compileFile(n)
+ case ast.Decl:
+ c.compileDecl(n)
+ case ast.Expr:
+ c.compileExpr(n)
+ case ast.Stmt:
+ c.compileStmt(n)
+ case *ast.ValueSpec:
+ c.compileValueSpec(n)
+ case stmtSlice:
+ c.compileStmtSlice(n)
+ case declSlice:
+ c.compileDeclSlice(n)
+ case ExprSlice:
+ c.compileExprSlice(n)
+ case *rangeClause:
+ c.compileRangeClause(n)
+ case *rangeHeader:
+ c.compileRangeHeader(n)
+ default:
+ panic(c.errorf(n, "compileNode: unexpected %T", n))
+ }
+}
+
+func (c *compiler) compileOptStmt(n ast.Stmt) {
+ if exprStmt, ok := n.(*ast.ExprStmt); ok {
+ if ident, ok := exprStmt.X.(*ast.Ident); ok && isWildName(ident.Name) {
+ c.compileWildIdent(ident, true)
+ return
+ }
+ }
+ c.compileStmt(n)
+}
+
+func (c *compiler) compileOptExpr(n ast.Expr) {
+ if ident, ok := n.(*ast.Ident); ok && isWildName(ident.Name) {
+ c.compileWildIdent(ident, true)
+ return
+ }
+ c.compileExpr(n)
+}
+
+func (c *compiler) compileOptFieldList(n *ast.FieldList) {
+ if len(n.List) == 1 {
+ if ident, ok := n.List[0].Type.(*ast.Ident); ok && isWildName(ident.Name) && len(n.List[0].Names) == 0 {
+ // `func (...) $*result` - result could be anything
+ // `func (...) $result` - result is a field list of 1 element
+ info := decodeWildName(ident.Name)
+ switch {
+ case info.Seq:
+ c.compileWildIdent(ident, true)
+ case info.Name == "_":
+ c.emitInstOp(opFieldNode)
+ default:
+ c.emitInst(instruction{
+ op: opNamedFieldNode,
+ valueIndex: c.internVar(n, info.Name),
+ })
+ }
+ return
+ }
+ }
+ c.compileFieldList(n)
+}
+
+func (c *compiler) compileFieldList(n *ast.FieldList) {
+ c.emitInstOp(opFieldList)
+ for _, x := range n.List {
+ c.compileField(x)
+ }
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileField(n *ast.Field) {
+ switch {
+ case len(n.Names) == 0:
+ if ident, ok := n.Type.(*ast.Ident); ok && isWildName(ident.Name) {
+ c.compileWildIdent(ident, false)
+ return
+ }
+ c.emitInstOp(opUnnamedField)
+ case len(n.Names) == 1:
+ name := n.Names[0]
+ if isWildName(name.Name) {
+ c.emitInstOp(opField)
+ c.compileWildIdent(name, false)
+ } else {
+ c.emitInst(instruction{
+ op: opSimpleField,
+ valueIndex: c.internString(name, name.Name),
+ })
+ }
+ default:
+ c.emitInstOp(opMultiField)
+ for _, name := range n.Names {
+ c.compileIdent(name)
+ }
+ c.emitInstOp(opEnd)
+ }
+ c.compileExpr(n.Type)
+}
+
+func (c *compiler) compileValueSpec(spec *ast.ValueSpec) {
+ switch {
+ case spec.Type == nil && len(spec.Values) == 0:
+ if isWildName(spec.Names[0].String()) {
+ c.compileIdent(spec.Names[0])
+ return
+ }
+ c.emitInstOp(opValueSpec)
+ case spec.Type == nil:
+ c.emitInstOp(opValueInitSpec)
+ case len(spec.Values) == 0:
+ c.emitInstOp(opTypedValueSpec)
+ default:
+ c.emitInstOp(opTypedValueInitSpec)
+ }
+ for _, name := range spec.Names {
+ c.compileIdent(name)
+ }
+ c.emitInstOp(opEnd)
+ if spec.Type != nil {
+ c.compileOptExpr(spec.Type)
+ }
+ if len(spec.Values) != 0 {
+ for _, v := range spec.Values {
+ c.compileExpr(v)
+ }
+ c.emitInstOp(opEnd)
+ }
+}
+
+func (c *compiler) compileTypeSpec(spec *ast.TypeSpec) {
+ c.emitInstOp(pickOp(spec.Assign.IsValid(), opTypeAliasSpec, opTypeSpec))
+ c.compileIdent(spec.Name)
+ c.compileExpr(spec.Type)
+}
+
+func (c *compiler) compileFile(n *ast.File) {
+ if len(n.Imports) == 0 && len(n.Decls) == 0 {
+ c.emitInstOp(opEmptyPackage)
+ c.compileIdent(n.Name)
+ return
+ }
+
+ panic(c.errorf(n, "compileFile: unsupported file pattern"))
+}
+
+func (c *compiler) compileDecl(n ast.Decl) {
+ switch n := n.(type) {
+ case *ast.FuncDecl:
+ c.compileFuncDecl(n)
+ case *ast.GenDecl:
+ c.compileGenDecl(n)
+
+ default:
+ panic(c.errorf(n, "compileDecl: unexpected %T", n))
+ }
+}
+
+func (c *compiler) compileFuncDecl(n *ast.FuncDecl) {
+ if n.Recv == nil {
+ c.emitInstOp(pickOp(n.Body == nil, opFuncProtoDecl, opFuncDecl))
+ } else {
+ c.emitInstOp(pickOp(n.Body == nil, opMethodProtoDecl, opMethodDecl))
+ }
+
+ if n.Recv != nil {
+ c.compileFieldList(n.Recv)
+ }
+ c.compileIdent(n.Name)
+ c.compileFuncType(n.Type)
+ if n.Body != nil {
+ c.compileBlockStmt(n.Body)
+ }
+}
+
+func (c *compiler) compileGenDecl(n *ast.GenDecl) {
+ if c.insideStmtList {
+ c.emitInstOp(opDeclStmt)
+ }
+
+ switch n.Tok {
+ case token.CONST, token.VAR:
+ c.emitInstOp(pickOp(n.Tok == token.CONST, opConstDecl, opVarDecl))
+ for _, spec := range n.Specs {
+ c.compileValueSpec(spec.(*ast.ValueSpec))
+ }
+ c.emitInstOp(opEnd)
+ case token.TYPE:
+ c.emitInstOp(opTypeDecl)
+ for _, spec := range n.Specs {
+ c.compileTypeSpec(spec.(*ast.TypeSpec))
+ }
+ c.emitInstOp(opEnd)
+
+ default:
+ panic(c.errorf(n, "unexpected gen decl"))
+ }
+}
+
+func (c *compiler) compileExpr(n ast.Expr) {
+ switch n := n.(type) {
+ case *ast.BasicLit:
+ c.compileBasicLit(n)
+ case *ast.BinaryExpr:
+ c.compileBinaryExpr(n)
+ case *ast.IndexExpr:
+ c.compileIndexExpr(n)
+ case *ast.Ident:
+ c.compileIdent(n)
+ case *ast.CallExpr:
+ c.compileCallExpr(n)
+ case *ast.UnaryExpr:
+ c.compileUnaryExpr(n)
+ case *ast.StarExpr:
+ c.compileStarExpr(n)
+ case *ast.ParenExpr:
+ c.compileParenExpr(n)
+ case *ast.SliceExpr:
+ c.compileSliceExpr(n)
+ case *ast.StructType:
+ c.compileStructType(n)
+ case *ast.InterfaceType:
+ c.compileInterfaceType(n)
+ case *ast.FuncType:
+ c.compileFuncType(n)
+ case *ast.ArrayType:
+ c.compileArrayType(n)
+ case *ast.MapType:
+ c.compileMapType(n)
+ case *ast.ChanType:
+ c.compileChanType(n)
+ case *ast.CompositeLit:
+ c.compileCompositeLit(n)
+ case *ast.FuncLit:
+ c.compileFuncLit(n)
+ case *ast.Ellipsis:
+ c.compileEllipsis(n)
+ case *ast.KeyValueExpr:
+ c.compileKeyValueExpr(n)
+ case *ast.SelectorExpr:
+ c.compileSelectorExpr(n)
+ case *ast.TypeAssertExpr:
+ c.compileTypeAssertExpr(n)
+
+ default:
+ panic(c.errorf(n, "compileExpr: unexpected %T", n))
+ }
+}
+
+func (c *compiler) compileBasicLit(n *ast.BasicLit) {
+ if !c.config.Strict {
+ v := literalValue(n)
+ if v == nil {
+ panic(c.errorf(n, "can't convert %s (%s) value", n.Value, n.Kind))
+ }
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: opBasicLit,
+ valueIndex: c.internIface(n, v),
+ })
+ return
+ }
+
+ var inst instruction
+ switch n.Kind {
+ case token.INT:
+ inst.op = opStrictIntLit
+ case token.FLOAT:
+ inst.op = opStrictFloatLit
+ case token.STRING:
+ inst.op = opStrictStringLit
+ case token.CHAR:
+ inst.op = opStrictCharLit
+ default:
+ inst.op = opStrictComplexLit
+ }
+ inst.valueIndex = c.internString(n, n.Value)
+ c.prog.insts = append(c.prog.insts, inst)
+}
+
+func (c *compiler) compileBinaryExpr(n *ast.BinaryExpr) {
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: opBinaryExpr,
+ value: c.toUint8(n, int(n.Op)),
+ })
+ c.compileExpr(n.X)
+ c.compileExpr(n.Y)
+}
+
+func (c *compiler) compileIndexExpr(n *ast.IndexExpr) {
+ c.emitInstOp(opIndexExpr)
+ c.compileExpr(n.X)
+ c.compileExpr(n.Index)
+}
+
+func (c *compiler) compileWildIdent(n *ast.Ident, optional bool) {
+ info := decodeWildName(n.Name)
+ var inst instruction
+ switch {
+ case info.Name == "_" && !info.Seq:
+ inst.op = opNode
+ case info.Name == "_" && info.Seq:
+ inst.op = pickOp(optional, opOptNode, opNodeSeq)
+ case info.Name != "_" && !info.Seq:
+ inst.op = opNamedNode
+ inst.valueIndex = c.internVar(n, info.Name)
+ default:
+ inst.op = pickOp(optional, opNamedOptNode, opNamedNodeSeq)
+ inst.valueIndex = c.internVar(n, info.Name)
+ }
+ c.prog.insts = append(c.prog.insts, inst)
+}
+
+func (c *compiler) compileIdent(n *ast.Ident) {
+ if isWildName(n.Name) {
+ c.compileWildIdent(n, false)
+ return
+ }
+
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: opIdent,
+ valueIndex: c.internString(n, n.Name),
+ })
+}
+
+func (c *compiler) compileExprMembers(list []ast.Expr) {
+ isSimple := len(list) <= 255
+ if isSimple {
+ for _, x := range list {
+ if decodeWildNode(x).Seq {
+ isSimple = false
+ break
+ }
+ }
+ }
+
+ if isSimple {
+ c.emitInst(instruction{
+ op: opSimpleArgList,
+ value: uint8(len(list)),
+ })
+ for _, x := range list {
+ c.compileExpr(x)
+ }
+ } else {
+ c.emitInstOp(opArgList)
+ for _, x := range list {
+ c.compileExpr(x)
+ }
+ c.emitInstOp(opEnd)
+ }
+}
+
+func (c *compiler) compileCallExpr(n *ast.CallExpr) {
+ canBeVariadic := func(n *ast.CallExpr) bool {
+ if len(n.Args) == 0 {
+ return false
+ }
+ lastArg, ok := n.Args[len(n.Args)-1].(*ast.Ident)
+ if !ok {
+ return false
+ }
+ return isWildName(lastArg.Name) && decodeWildName(lastArg.Name).Seq
+ }
+
+ op := opNonVariadicCallExpr
+ if n.Ellipsis.IsValid() {
+ op = opVariadicCallExpr
+ } else if canBeVariadic(n) {
+ op = opCallExpr
+ }
+
+ c.emitInstOp(op)
+ c.compileSymbol(n.Fun)
+ c.compileExprMembers(n.Args)
+}
+
+// compileSymbol is mostly like a normal compileExpr, but it's used
+// in places where we can find a type/function symbol.
+//
+// For example, in function call expressions a called function expression
+// can look like `fmt.Sprint`. It will be compiled as a special
+// selector expression that requires `fmt` to be a package as opposed
+// to only check that it's an identifier with "fmt" value.
+func (c *compiler) compileSymbol(sym ast.Expr) {
+ compilePkgSymbol := func(c *compiler, sym ast.Expr) bool {
+ e, ok := sym.(*ast.SelectorExpr)
+ if !ok {
+ return false
+ }
+ ident, ok := e.X.(*ast.Ident)
+ if !ok || isWildName(e.Sel.Name) {
+ return false
+ }
+ pkgPath := c.config.Imports[ident.Name]
+ if pkgPath == "" && stdinfo.Packages[ident.Name] != "" {
+ pkgPath = stdinfo.Packages[ident.Name]
+ }
+ if pkgPath == "" {
+ return false
+ }
+ c.emitInst(instruction{
+ op: opSimpleSelectorExpr,
+ valueIndex: c.internString(e.Sel, e.Sel.String()),
+ })
+ c.emitInst(instruction{
+ op: opPkg,
+ valueIndex: c.internString(ident, pkgPath),
+ })
+ return true
+ }
+
+ if c.config.WithTypes {
+ if compilePkgSymbol(c, sym) {
+ return
+ }
+ }
+
+ c.compileExpr(sym)
+}
+
+func (c *compiler) compileUnaryExpr(n *ast.UnaryExpr) {
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: opUnaryExpr,
+ value: c.toUint8(n, int(n.Op)),
+ })
+ c.compileExpr(n.X)
+}
+
+func (c *compiler) compileStarExpr(n *ast.StarExpr) {
+ c.emitInstOp(opStarExpr)
+ c.compileExpr(n.X)
+}
+
+func (c *compiler) compileParenExpr(n *ast.ParenExpr) {
+ c.emitInstOp(opParenExpr)
+ c.compileExpr(n.X)
+}
+
+func (c *compiler) compileSliceExpr(n *ast.SliceExpr) {
+ switch {
+ case n.Low == nil && n.High == nil && !n.Slice3:
+ c.emitInstOp(opSliceExpr)
+ c.compileOptExpr(n.X)
+ case n.Low != nil && n.High == nil && !n.Slice3:
+ c.emitInstOp(opSliceFromExpr)
+ c.compileOptExpr(n.X)
+ c.compileOptExpr(n.Low)
+ case n.Low == nil && n.High != nil && !n.Slice3:
+ c.emitInstOp(opSliceToExpr)
+ c.compileOptExpr(n.X)
+ c.compileOptExpr(n.High)
+ case n.Low != nil && n.High != nil && !n.Slice3:
+ c.emitInstOp(opSliceFromToExpr)
+ c.compileOptExpr(n.X)
+ c.compileOptExpr(n.Low)
+ c.compileOptExpr(n.High)
+ case n.Low == nil && n.Slice3:
+ c.emitInstOp(opSliceToCapExpr)
+ c.compileOptExpr(n.X)
+ c.compileOptExpr(n.High)
+ c.compileOptExpr(n.Max)
+ case n.Low != nil && n.Slice3:
+ c.emitInstOp(opSliceFromToCapExpr)
+ c.compileOptExpr(n.X)
+ c.compileOptExpr(n.Low)
+ c.compileOptExpr(n.High)
+ c.compileOptExpr(n.Max)
+ default:
+ panic(c.errorf(n, "unexpected slice expr"))
+ }
+}
+
+func (c *compiler) compileStructType(n *ast.StructType) {
+ c.emitInstOp(opStructType)
+ c.compileOptFieldList(n.Fields)
+}
+
+func (c *compiler) compileInterfaceType(n *ast.InterfaceType) {
+ c.emitInstOp(opInterfaceType)
+ c.compileOptFieldList(n.Methods)
+}
+
+func (c *compiler) compileFuncType(n *ast.FuncType) {
+ void := n.Results == nil || len(n.Results.List) == 0
+ if void {
+ c.emitInstOp(opVoidFuncType)
+ } else {
+ c.emitInstOp(opFuncType)
+ }
+ c.compileOptFieldList(n.Params)
+ if !void {
+ c.compileOptFieldList(n.Results)
+ }
+}
+
+func (c *compiler) compileArrayType(n *ast.ArrayType) {
+ if n.Len == nil {
+ c.emitInstOp(opSliceType)
+ c.compileExpr(n.Elt)
+ } else {
+ c.emitInstOp(opArrayType)
+ c.compileExpr(n.Len)
+ c.compileExpr(n.Elt)
+ }
+}
+
+func (c *compiler) compileMapType(n *ast.MapType) {
+ c.emitInstOp(opMapType)
+ c.compileExpr(n.Key)
+ c.compileExpr(n.Value)
+}
+
+func (c *compiler) compileChanType(n *ast.ChanType) {
+ c.emitInst(instruction{
+ op: opChanType,
+ value: c.toUint8(n, int(n.Dir)),
+ })
+ c.compileExpr(n.Value)
+}
+
+func (c *compiler) compileCompositeLit(n *ast.CompositeLit) {
+ if n.Type == nil {
+ c.emitInstOp(opCompositeLit)
+ } else {
+ c.emitInstOp(opTypedCompositeLit)
+ c.compileExpr(n.Type)
+ }
+ for _, elt := range n.Elts {
+ c.compileExpr(elt)
+ }
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileFuncLit(n *ast.FuncLit) {
+ c.emitInstOp(opFuncLit)
+ c.compileFuncType(n.Type)
+ c.compileBlockStmt(n.Body)
+}
+
+func (c *compiler) compileEllipsis(n *ast.Ellipsis) {
+ if n.Elt == nil {
+ c.emitInstOp(opEllipsis)
+ } else {
+ c.emitInstOp(opTypedEllipsis)
+ c.compileExpr(n.Elt)
+ }
+}
+
+func (c *compiler) compileKeyValueExpr(n *ast.KeyValueExpr) {
+ c.emitInstOp(opKeyValueExpr)
+ c.compileExpr(n.Key)
+ c.compileExpr(n.Value)
+}
+
+func (c *compiler) compileSelectorExpr(n *ast.SelectorExpr) {
+ if isWildName(n.Sel.Name) {
+ c.emitInstOp(opSelectorExpr)
+ c.compileWildIdent(n.Sel, false)
+ c.compileExpr(n.X)
+ return
+ }
+
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: opSimpleSelectorExpr,
+ valueIndex: c.internString(n.Sel, n.Sel.String()),
+ })
+ c.compileExpr(n.X)
+}
+
+func (c *compiler) compileTypeAssertExpr(n *ast.TypeAssertExpr) {
+ if n.Type != nil {
+ c.emitInstOp(opTypeAssertExpr)
+ c.compileExpr(n.X)
+ c.compileExpr(n.Type)
+ } else {
+ c.emitInstOp(opTypeSwitchAssertExpr)
+ c.compileExpr(n.X)
+ }
+}
+
+func (c *compiler) compileStmt(n ast.Stmt) {
+ switch n := n.(type) {
+ case *ast.AssignStmt:
+ c.compileAssignStmt(n)
+ case *ast.BlockStmt:
+ c.compileBlockStmt(n)
+ case *ast.ExprStmt:
+ c.compileExprStmt(n)
+ case *ast.IfStmt:
+ c.compileIfStmt(n)
+ case *ast.CaseClause:
+ c.compileCaseClause(n)
+ case *ast.SwitchStmt:
+ c.compileSwitchStmt(n)
+ case *ast.TypeSwitchStmt:
+ c.compileTypeSwitchStmt(n)
+ case *ast.SelectStmt:
+ c.compileSelectStmt(n)
+ case *ast.ForStmt:
+ c.compileForStmt(n)
+ case *ast.RangeStmt:
+ c.compileRangeStmt(n)
+ case *ast.IncDecStmt:
+ c.compileIncDecStmt(n)
+ case *ast.EmptyStmt:
+ c.compileEmptyStmt(n)
+ case *ast.ReturnStmt:
+ c.compileReturnStmt(n)
+ case *ast.BranchStmt:
+ c.compileBranchStmt(n)
+ case *ast.LabeledStmt:
+ c.compileLabeledStmt(n)
+ case *ast.GoStmt:
+ c.compileGoStmt(n)
+ case *ast.DeferStmt:
+ c.compileDeferStmt(n)
+ case *ast.SendStmt:
+ c.compileSendStmt(n)
+ case *ast.DeclStmt:
+ c.compileDecl(n.Decl)
+
+ default:
+ panic(c.errorf(n, "compileStmt: unexpected %T", n))
+ }
+}
+
+func (c *compiler) compileAssignStmt(n *ast.AssignStmt) {
+ if len(n.Lhs) == 1 && len(n.Rhs) == 1 {
+ lhsInfo := decodeWildNode(n.Lhs[0])
+ rhsInfo := decodeWildNode(n.Rhs[0])
+ if !lhsInfo.Seq && !rhsInfo.Seq {
+ c.emitInst(instruction{
+ op: opAssignStmt,
+ value: uint8(n.Tok),
+ })
+ c.compileExpr(n.Lhs[0])
+ c.compileExpr(n.Rhs[0])
+ return
+ }
+ }
+
+ c.emitInst(instruction{
+ op: opMultiAssignStmt,
+ value: uint8(n.Tok),
+ })
+ for _, x := range n.Lhs {
+ c.compileExpr(x)
+ }
+ c.emitInstOp(opEnd)
+ for _, x := range n.Rhs {
+ c.compileExpr(x)
+ }
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileBlockStmt(n *ast.BlockStmt) {
+ c.emitInstOp(opBlockStmt)
+ insideStmtList := c.insideStmtList
+ c.insideStmtList = true
+ for _, elt := range n.List {
+ c.compileStmt(elt)
+ }
+ c.insideStmtList = insideStmtList
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileExprStmt(n *ast.ExprStmt) {
+ if ident, ok := n.X.(*ast.Ident); ok && isWildName(ident.Name) {
+ c.compileIdent(ident)
+ } else {
+ c.emitInstOp(opExprStmt)
+ c.compileExpr(n.X)
+ }
+}
+
+func (c *compiler) compileIfStmt(n *ast.IfStmt) {
+ // Check for the special case: `if $*_ ...` should match all if statements.
+ if ident, ok := n.Cond.(*ast.Ident); ok && n.Init == nil && isWildName(ident.Name) {
+ info := decodeWildName(ident.Name)
+ if info.Seq && info.Name == "_" {
+ // Set Init to Cond, change cond from $*_ to $_.
+ n.Init = &ast.ExprStmt{X: n.Cond}
+ cond := &ast.Ident{Name: encodeWildName(info.Name, false)}
+ n.Cond = cond
+ c.compileIfStmt(n)
+ return
+ }
+ // Named $* is harder and slower.
+ if info.Seq {
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: pickOp(n.Else == nil, opIfNamedOptStmt, opIfNamedOptElseStmt),
+ valueIndex: c.internVar(ident, info.Name),
+ })
+ c.compileStmt(n.Body)
+ if n.Else != nil {
+ c.compileStmt(n.Else)
+ }
+ return
+ }
+ }
+
+ switch {
+ case n.Init == nil && n.Else == nil:
+ c.emitInstOp(opIfStmt)
+ c.compileExpr(n.Cond)
+ c.compileStmt(n.Body)
+ case n.Init != nil && n.Else == nil:
+ c.emitInstOp(opIfInitStmt)
+ c.compileOptStmt(n.Init)
+ c.compileExpr(n.Cond)
+ c.compileStmt(n.Body)
+ case n.Init == nil && n.Else != nil:
+ c.emitInstOp(opIfElseStmt)
+ c.compileExpr(n.Cond)
+ c.compileStmt(n.Body)
+ c.compileStmt(n.Else)
+ case n.Init != nil && n.Else != nil:
+ c.emitInstOp(opIfInitElseStmt)
+ c.compileOptStmt(n.Init)
+ c.compileExpr(n.Cond)
+ c.compileStmt(n.Body)
+ c.compileStmt(n.Else)
+
+ default:
+ panic(c.errorf(n, "unexpected if stmt"))
+ }
+}
+
+func (c *compiler) compileCommClause(n *ast.CommClause) {
+ c.emitInstOp(pickOp(n.Comm == nil, opDefaultCommClause, opCommClause))
+ if n.Comm != nil {
+ c.compileStmt(n.Comm)
+ }
+ for _, x := range n.Body {
+ c.compileStmt(x)
+ }
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileCaseClause(n *ast.CaseClause) {
+ c.emitInstOp(pickOp(n.List == nil, opDefaultCaseClause, opCaseClause))
+ if n.List != nil {
+ for _, x := range n.List {
+ c.compileExpr(x)
+ }
+ c.emitInstOp(opEnd)
+ }
+ for _, x := range n.Body {
+ c.compileStmt(x)
+ }
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileSwitchBody(n *ast.BlockStmt) {
+ wildcardCase := func(cc *ast.CaseClause) *ast.Ident {
+ if len(cc.List) != 1 || len(cc.Body) != 1 {
+ return nil
+ }
+ v, ok := cc.List[0].(*ast.Ident)
+ if !ok || !isWildName(v.Name) {
+ return nil
+ }
+ bodyStmt, ok := cc.Body[0].(*ast.ExprStmt)
+ if !ok {
+ return nil
+ }
+ bodyIdent, ok := bodyStmt.X.(*ast.Ident)
+ if !ok || bodyIdent.Name != "gogrep_body" {
+ return nil
+ }
+ return v
+ }
+ for _, cc := range n.List {
+ cc := cc.(*ast.CaseClause)
+ wildcard := wildcardCase(cc)
+ if wildcard == nil {
+ c.compileCaseClause(cc)
+ continue
+ }
+ c.compileWildIdent(wildcard, false)
+ }
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileSwitchStmt(n *ast.SwitchStmt) {
+ var op operation
+ switch {
+ case n.Init == nil && n.Tag == nil:
+ op = opSwitchStmt
+ case n.Init == nil && n.Tag != nil:
+ op = opSwitchTagStmt
+ case n.Init != nil && n.Tag == nil:
+ op = opSwitchInitStmt
+ default:
+ op = opSwitchInitTagStmt
+ }
+
+ c.emitInstOp(op)
+ if n.Init != nil {
+ c.compileOptStmt(n.Init)
+ }
+ if n.Tag != nil {
+ c.compileOptExpr(n.Tag)
+ }
+ c.compileSwitchBody(n.Body)
+}
+
+func (c *compiler) compileTypeSwitchStmt(n *ast.TypeSwitchStmt) {
+ c.emitInstOp(pickOp(n.Init == nil, opTypeSwitchStmt, opTypeSwitchInitStmt))
+ if n.Init != nil {
+ c.compileOptStmt(n.Init)
+ }
+ c.compileStmt(n.Assign)
+ c.compileSwitchBody(n.Body)
+}
+
+func (c *compiler) compileSelectStmt(n *ast.SelectStmt) {
+ c.emitInstOp(opSelectStmt)
+
+ wildcardCase := func(cc *ast.CommClause) *ast.Ident {
+ if cc.Comm == nil {
+ return nil
+ }
+ vStmt, ok := cc.Comm.(*ast.ExprStmt)
+ if !ok {
+ return nil
+ }
+ v, ok := vStmt.X.(*ast.Ident)
+ if !ok || !isWildName(v.Name) {
+ return nil
+ }
+ bodyStmt, ok := cc.Body[0].(*ast.ExprStmt)
+ if !ok {
+ return nil
+ }
+ bodyIdent, ok := bodyStmt.X.(*ast.Ident)
+ if !ok || bodyIdent.Name != "gogrep_body" {
+ return nil
+ }
+ return v
+ }
+ for _, cc := range n.Body.List {
+ cc := cc.(*ast.CommClause)
+ wildcard := wildcardCase(cc)
+ if wildcard == nil {
+ c.compileCommClause(cc)
+ continue
+ }
+ c.compileWildIdent(wildcard, false)
+ }
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileForStmt(n *ast.ForStmt) {
+ var op operation
+ switch {
+ case n.Init == nil && n.Cond == nil && n.Post == nil:
+ op = opForStmt
+ case n.Init == nil && n.Cond == nil && n.Post != nil:
+ op = opForPostStmt
+ case n.Init == nil && n.Cond != nil && n.Post == nil:
+ op = opForCondStmt
+ case n.Init == nil && n.Cond != nil && n.Post != nil:
+ op = opForCondPostStmt
+ case n.Init != nil && n.Cond == nil && n.Post == nil:
+ op = opForInitStmt
+ case n.Init != nil && n.Cond == nil && n.Post != nil:
+ op = opForInitPostStmt
+ case n.Init != nil && n.Cond != nil && n.Post == nil:
+ op = opForInitCondStmt
+ default:
+ op = opForInitCondPostStmt
+ }
+
+ c.emitInstOp(op)
+ if n.Init != nil {
+ c.compileOptStmt(n.Init)
+ }
+ if n.Cond != nil {
+ c.compileOptExpr(n.Cond)
+ }
+ if n.Post != nil {
+ c.compileOptStmt(n.Post)
+ }
+ c.compileBlockStmt(n.Body)
+}
+
+func (c *compiler) compileRangeStmt(n *ast.RangeStmt) {
+ switch {
+ case n.Key == nil && n.Value == nil:
+ c.emitInstOp(opRangeStmt)
+ c.compileExpr(n.X)
+ c.compileStmt(n.Body)
+ case n.Key != nil && n.Value == nil:
+ c.emitInst(instruction{
+ op: opRangeKeyStmt,
+ value: c.toUint8(n, int(n.Tok)),
+ })
+ c.compileExpr(n.Key)
+ c.compileExpr(n.X)
+ c.compileStmt(n.Body)
+ case n.Key != nil && n.Value != nil:
+ c.emitInst(instruction{
+ op: opRangeKeyValueStmt,
+ value: c.toUint8(n, int(n.Tok)),
+ })
+ c.compileExpr(n.Key)
+ c.compileExpr(n.Value)
+ c.compileExpr(n.X)
+ c.compileStmt(n.Body)
+ default:
+ panic(c.errorf(n, "unexpected range stmt"))
+ }
+}
+
+func (c *compiler) compileIncDecStmt(n *ast.IncDecStmt) {
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: opIncDecStmt,
+ value: c.toUint8(n, int(n.Tok)),
+ })
+ c.compileExpr(n.X)
+}
+
+func (c *compiler) compileEmptyStmt(n *ast.EmptyStmt) {
+ _ = n // unused
+ c.emitInstOp(opEmptyStmt)
+}
+
+func (c *compiler) compileReturnStmt(n *ast.ReturnStmt) {
+ c.emitInstOp(opReturnStmt)
+ for _, x := range n.Results {
+ c.compileExpr(x)
+ }
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileBranchStmt(n *ast.BranchStmt) {
+ if n.Label != nil {
+ if isWildName(n.Label.Name) {
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: opLabeledBranchStmt,
+ value: c.toUint8(n, int(n.Tok)),
+ })
+ c.compileWildIdent(n.Label, false)
+ } else {
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: opSimpleLabeledBranchStmt,
+ value: c.toUint8(n, int(n.Tok)),
+ valueIndex: c.internString(n.Label, n.Label.Name),
+ })
+ }
+ return
+ }
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: opBranchStmt,
+ value: c.toUint8(n, int(n.Tok)),
+ })
+}
+
+func (c *compiler) compileLabeledStmt(n *ast.LabeledStmt) {
+ if isWildName(n.Label.Name) {
+ c.emitInstOp(opLabeledStmt)
+ c.compileWildIdent(n.Label, false)
+ c.compileStmt(n.Stmt)
+ return
+ }
+
+ c.prog.insts = append(c.prog.insts, instruction{
+ op: opSimpleLabeledStmt,
+ valueIndex: c.internString(n.Label, n.Label.Name),
+ })
+ c.compileStmt(n.Stmt)
+}
+
+func (c *compiler) compileGoStmt(n *ast.GoStmt) {
+ c.emitInstOp(opGoStmt)
+ c.compileExpr(n.Call)
+}
+
+func (c *compiler) compileDeferStmt(n *ast.DeferStmt) {
+ c.emitInstOp(opDeferStmt)
+ c.compileExpr(n.Call)
+}
+
+func (c *compiler) compileSendStmt(n *ast.SendStmt) {
+ c.emitInstOp(opSendStmt)
+ c.compileExpr(n.Chan)
+ c.compileExpr(n.Value)
+}
+
+func (c *compiler) compileDeclSlice(decls declSlice) {
+ c.emitInstOp(opMultiDecl)
+ for _, n := range decls {
+ c.compileDecl(n)
+ }
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileStmtSlice(stmts stmtSlice) {
+ c.emitInstOp(opMultiStmt)
+ insideStmtList := c.insideStmtList
+ c.insideStmtList = true
+ for _, n := range stmts {
+ c.compileStmt(n)
+ }
+ c.insideStmtList = insideStmtList
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileExprSlice(exprs ExprSlice) {
+ c.emitInstOp(opMultiExpr)
+ for _, n := range exprs {
+ c.compileExpr(n)
+ }
+ c.emitInstOp(opEnd)
+}
+
+func (c *compiler) compileRangeClause(clause *rangeClause) {
+ c.emitInstOp(opRangeClause)
+ c.compileExpr(clause.X)
+}
+
+func (c *compiler) compileRangeHeader(h *rangeHeader) {
+ n := h.Node
+ switch {
+ case n.Key == nil && n.Value == nil:
+ c.emitInstOp(opRangeHeader)
+ c.compileExpr(n.X)
+ case n.Key != nil && n.Value == nil:
+ c.emitInst(instruction{
+ op: opRangeKeyHeader,
+ value: c.toUint8(n, int(n.Tok)),
+ })
+ c.compileExpr(n.Key)
+ c.compileExpr(n.X)
+ case n.Key != nil && n.Value != nil:
+ c.emitInst(instruction{
+ op: opRangeKeyValueHeader,
+ value: c.toUint8(n, int(n.Tok)),
+ })
+ c.compileExpr(n.Key)
+ c.compileExpr(n.Value)
+ c.compileExpr(n.X)
+ default:
+ panic(c.errorf(n, "unexpected range header"))
+ }
+}
+
+func pickOp(cond bool, ifTrue, ifFalse operation) operation {
+ if cond {
+ return ifTrue
+ }
+ return ifFalse
+}
+
+func fitsUint8(v int) bool {
+ return v >= 0 && v <= 0xff
+}
diff --git a/vendor/github.com/quasilyte/gogrep/compile_import.go b/vendor/github.com/quasilyte/gogrep/compile_import.go
new file mode 100644
index 000000000..ab0dd12a7
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/compile_import.go
@@ -0,0 +1,57 @@
+package gogrep
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+func compileImportPattern(config CompileConfig) (*Pattern, PatternInfo, error) {
+ // TODO: figure out how to compile it as a part of a normal pattern compilation?
+ // This is an adhoc solution to a problem.
+
+ readIdent := func(s string) (varname, rest string) {
+ first := true
+ var offset int
+ for _, ch := range s {
+ ok := unicode.IsLetter(ch) ||
+ ch == '_' ||
+ (!first && unicode.IsDigit(ch))
+ if !ok {
+ break
+ }
+ offset += utf8.RuneLen(ch)
+ first = false
+ }
+ return s[:offset], s[offset:]
+ }
+
+ info := newPatternInfo()
+ src := config.Src
+ src = src[len("import $"):]
+ if src == "" {
+ return nil, info, errors.New("expected ident after $, found EOF")
+ }
+ varname, rest := readIdent(src)
+ if strings.TrimSpace(rest) != "" {
+ return nil, info, fmt.Errorf("unexpected %s", rest)
+ }
+ var p program
+ if varname != "_" {
+ info.Vars[src] = struct{}{}
+ p.strings = []string{varname}
+ p.insts = []instruction{
+ {op: opImportDecl},
+ {op: opNamedNodeSeq, valueIndex: 0},
+ {op: opEnd},
+ }
+ } else {
+ p.insts = []instruction{
+ {op: opAnyImportDecl},
+ }
+ }
+ m := matcher{prog: &p, insts: p.insts}
+ return &Pattern{m: &m}, info, nil
+}
diff --git a/vendor/github.com/quasilyte/gogrep/gen_operations.go b/vendor/github.com/quasilyte/gogrep/gen_operations.go
new file mode 100644
index 000000000..8de59980b
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/gen_operations.go
@@ -0,0 +1,357 @@
+//go:build main
+// +build main
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+ "strings"
+ "text/template"
+)
+
+var opPrototypes = []operationProto{
+ {name: "Node", tag: "Node"},
+ {name: "NamedNode", tag: "Node", valueIndex: "strings | wildcard name"},
+ {name: "NodeSeq"},
+ {name: "NamedNodeSeq", valueIndex: "strings | wildcard name"},
+ {name: "OptNode"},
+ {name: "NamedOptNode", valueIndex: "strings | wildcard name"},
+
+ {name: "FieldNode", tag: "Node"},
+ {name: "NamedFieldNode", tag: "Node", valueIndex: "strings | wildcard name"},
+
+ {name: "MultiStmt", tag: "StmtList", args: "stmts...", example: "f(); g()"},
+ {name: "MultiExpr", tag: "ExprList", args: "exprs...", example: "f(), g()"},
+ {name: "MultiDecl", tag: "DeclList", args: "exprs...", example: "f(), g()"},
+
+ {name: "End"},
+
+ {name: "BasicLit", tag: "BasicLit", valueIndex: "ifaces | parsed literal value"},
+ {name: "StrictIntLit", tag: "BasicLit", valueIndex: "strings | raw literal value"},
+ {name: "StrictFloatLit", tag: "BasicLit", valueIndex: "strings | raw literal value"},
+ {name: "StrictCharLit", tag: "BasicLit", valueIndex: "strings | raw literal value"},
+ {name: "StrictStringLit", tag: "BasicLit", valueIndex: "strings | raw literal value"},
+ {name: "StrictComplexLit", tag: "BasicLit", valueIndex: "strings | raw literal value"},
+
+ {name: "Ident", tag: "Ident", valueIndex: "strings | ident name"},
+ {name: "Pkg", tag: "Ident", valueIndex: "strings | package path"},
+
+ {name: "IndexExpr", tag: "IndexExpr", args: "x expr"},
+
+ {name: "SliceExpr", tag: "SliceExpr", args: "x"},
+ {name: "SliceFromExpr", tag: "SliceExpr", args: "x from", example: "x[from:]"},
+ {name: "SliceToExpr", tag: "SliceExpr", args: "x to", example: "x[:to]"},
+ {name: "SliceFromToExpr", tag: "SliceExpr", args: "x from to", example: "x[from:to]"},
+ {name: "SliceToCapExpr", tag: "SliceExpr", args: "x from cap", example: "x[:from:cap]"},
+ {name: "SliceFromToCapExpr", tag: "SliceExpr", args: "x from to cap", example: "x[from:to:cap]"},
+
+ {name: "FuncLit", tag: "FuncLit", args: "type block"},
+
+ {name: "CompositeLit", tag: "CompositeLit", args: "elts...", example: "{elts...}"},
+ {name: "TypedCompositeLit", tag: "CompositeLit", args: "typ elts...", example: "typ{elts...}"},
+
+ {name: "SimpleSelectorExpr", tag: "SelectorExpr", args: "x", valueIndex: "strings | selector name"},
+ {name: "SelectorExpr", tag: "SelectorExpr", args: "x sel"},
+ {name: "TypeAssertExpr", tag: "TypeAssertExpr", args: "x typ"},
+ {name: "TypeSwitchAssertExpr", tag: "TypeAssertExpr", args: "x"},
+
+ {name: "StructType", tag: "StructType", args: "fields"},
+ {name: "InterfaceType", tag: "StructType", args: "fields"},
+ {name: "VoidFuncType", tag: "FuncType", args: "params"},
+ {name: "FuncType", tag: "FuncType", args: "params results"},
+ {name: "ArrayType", tag: "ArrayType", args: "length elem"},
+ {name: "SliceType", tag: "ArrayType", args: "elem"},
+ {name: "MapType", tag: "MapType", args: "key value"},
+ {name: "ChanType", tag: "ChanType", args: "value", value: "ast.ChanDir | channel direction"},
+ {name: "KeyValueExpr", tag: "KeyValueExpr", args: "key value"},
+
+ {name: "Ellipsis", tag: "Ellipsis"},
+ {name: "TypedEllipsis", tag: "Ellipsis", args: "type"},
+
+ {name: "StarExpr", tag: "StarExpr", args: "x"},
+ {name: "UnaryExpr", tag: "UnaryExpr", args: "x", value: "token.Token | unary operator"},
+ {name: "BinaryExpr", tag: "BinaryExpr", args: "x y", value: "token.Token | binary operator"},
+ {name: "ParenExpr", tag: "ParenExpr", args: "x"},
+
+ {
+ name: "ArgList",
+ args: "exprs...",
+ example: "1, 2, 3",
+ },
+ {
+ name: "SimpleArgList",
+ note: "Like ArgList, but pattern contains no $*",
+ args: "exprs[]",
+ value: "int | slice len",
+ example: "1, 2, 3",
+ },
+
+ {name: "VariadicCallExpr", tag: "CallExpr", args: "fn args", example: "f(1, xs...)"},
+ {name: "NonVariadicCallExpr", tag: "CallExpr", args: "fn args", example: "f(1, xs)"},
+ {name: "CallExpr", tag: "CallExpr", args: "fn args", example: "f(1, xs) or f(1, xs...)"},
+
+ {name: "AssignStmt", tag: "AssignStmt", args: "lhs rhs", value: "token.Token | ':=' or '='", example: "lhs := rhs()"},
+ {name: "MultiAssignStmt", tag: "AssignStmt", args: "lhs... rhs...", value: "token.Token | ':=' or '='", example: "lhs1, lhs2 := rhs()"},
+
+ {name: "BranchStmt", tag: "BranchStmt", args: "x", value: "token.Token | branch kind"},
+ {name: "SimpleLabeledBranchStmt", tag: "BranchStmt", args: "x", valueIndex: "strings | label name", value: "token.Token | branch kind"},
+ {name: "LabeledBranchStmt", tag: "BranchStmt", args: "label x", value: "token.Token | branch kind"},
+ {name: "SimpleLabeledStmt", tag: "LabeledStmt", args: "x", valueIndex: "strings | label name"},
+ {name: "LabeledStmt", tag: "LabeledStmt", args: "label x"},
+
+ {name: "BlockStmt", tag: "BlockStmt", args: "body..."},
+ {name: "ExprStmt", tag: "ExprStmt", args: "x"},
+
+ {name: "GoStmt", tag: "GoStmt", args: "x"},
+ {name: "DeferStmt", tag: "DeferStmt", args: "x"},
+
+ {name: "SendStmt", tag: "SendStmt", args: "ch value"},
+
+ {name: "EmptyStmt", tag: "EmptyStmt"},
+ {name: "IncDecStmt", tag: "IncDecStmt", args: "x", value: "token.Token | '++' or '--'"},
+ {name: "ReturnStmt", tag: "ReturnStmt", args: "results..."},
+
+ {name: "IfStmt", tag: "IfStmt", args: "cond block", example: "if cond {}"},
+ {name: "IfInitStmt", tag: "IfStmt", args: "init cond block", example: "if init; cond {}"},
+ {name: "IfElseStmt", tag: "IfStmt", args: "cond block else", example: "if cond {} else ..."},
+ {name: "IfInitElseStmt", tag: "IfStmt", args: "init cond block else", example: "if init; cond {} else ..."},
+ {name: "IfNamedOptStmt", tag: "IfStmt", args: "block", valueIndex: "strings | wildcard name", example: "if $*x {}"},
+ {name: "IfNamedOptElseStmt", tag: "IfStmt", args: "block else", valueIndex: "strings | wildcard name", example: "if $*x {} else ..."},
+
+ {name: "SwitchStmt", tag: "SwitchStmt", args: "body...", example: "switch {}"},
+ {name: "SwitchTagStmt", tag: "SwitchStmt", args: "tag body...", example: "switch tag {}"},
+ {name: "SwitchInitStmt", tag: "SwitchStmt", args: "init body...", example: "switch init; {}"},
+ {name: "SwitchInitTagStmt", tag: "SwitchStmt", args: "init tag body...", example: "switch init; tag {}"},
+
+ {name: "SelectStmt", tag: "SelectStmt", args: "body..."},
+
+ {name: "TypeSwitchStmt", tag: "TypeSwitchStmt", args: "x block", example: "switch x.(type) {}"},
+ {name: "TypeSwitchInitStmt", tag: "TypeSwitchStmt", args: "init x block", example: "switch init; x.(type) {}"},
+
+ {name: "CaseClause", tag: "CaseClause", args: "values... body..."},
+ {name: "DefaultCaseClause", tag: "CaseClause", args: "body..."},
+
+ {name: "CommClause", tag: "CommClause", args: "comm body..."},
+ {name: "DefaultCommClause", tag: "CommClause", args: "body..."},
+
+ {name: "ForStmt", tag: "ForStmt", args: "blocl", example: "for {}"},
+ {name: "ForPostStmt", tag: "ForStmt", args: "post block", example: "for ; ; post {}"},
+ {name: "ForCondStmt", tag: "ForStmt", args: "cond block", example: "for ; cond; {}"},
+ {name: "ForCondPostStmt", tag: "ForStmt", args: "cond post block", example: "for ; cond; post {}"},
+ {name: "ForInitStmt", tag: "ForStmt", args: "init block", example: "for init; ; {}"},
+ {name: "ForInitPostStmt", tag: "ForStmt", args: "init post block", example: "for init; ; post {}"},
+ {name: "ForInitCondStmt", tag: "ForStmt", args: "init cond block", example: "for init; cond; {}"},
+ {name: "ForInitCondPostStmt", tag: "ForStmt", args: "init cond post block", example: "for init; cond; post {}"},
+
+ {name: "RangeStmt", tag: "RangeStmt", args: "x block", example: "for range x {}"},
+ {name: "RangeKeyStmt", tag: "RangeStmt", args: "key x block", value: "token.Token | ':=' or '='", example: "for key := range x {}"},
+ {name: "RangeKeyValueStmt", tag: "RangeStmt", args: "key value x block", value: "token.Token | ':=' or '='", example: "for key, value := range x {}"},
+
+ {name: "RangeClause", tag: "RangeStmt", args: "x", example: "range x"},
+ {name: "RangeHeader", tag: "RangeStmt", args: "x", example: "for range x"},
+ {name: "RangeKeyHeader", tag: "RangeStmt", args: "key x", value: "token.Token | ':=' or '='", example: "for key := range x"},
+ {name: "RangeKeyValueHeader", tag: "RangeStmt", args: "key value x", value: "token.Token | ':=' or '='", example: "for key, value := range x"},
+
+ {name: "FieldList", args: "fields..."},
+ {name: "UnnamedField", args: "typ", example: "type"},
+ {name: "SimpleField", args: "typ", valueIndex: "strings | field name", example: "name type"},
+ {name: "Field", args: "name typ", example: "$name type"},
+ {name: "MultiField", args: "names... typ", example: "name1, name2 type"},
+
+ {name: "ValueSpec", tag: "ValueSpec", args: "value"},
+ {name: "ValueInitSpec", tag: "ValueSpec", args: "lhs... rhs...", example: "lhs = rhs"},
+ {name: "TypedValueInitSpec", tag: "ValueSpec", args: "lhs... type rhs...", example: "lhs typ = rhs"},
+ {name: "TypedValueSpec", tag: "ValueSpec", args: "lhs... type", example: "lhs typ"},
+
+ {name: "TypeSpec", tag: "TypeSpec", args: "name type", example: "name type"},
+ {name: "TypeAliasSpec", tag: "TypeSpec", args: "name type", example: "name = type"},
+
+ {name: "FuncDecl", tag: "FuncDecl", args: "name type block"},
+ {name: "MethodDecl", tag: "FuncDecl", args: "recv name type block"},
+ {name: "FuncProtoDecl", tag: "FuncDecl", args: "name type"},
+ {name: "MethodProtoDecl", tag: "FuncDecl", args: "recv name type"},
+
+ {name: "DeclStmt", tag: "DeclStmt", args: "decl"},
+ {name: "ConstDecl", tag: "GenDecl", args: "valuespecs..."},
+ {name: "VarDecl", tag: "GenDecl", args: "valuespecs..."},
+ {name: "TypeDecl", tag: "GenDecl", args: "typespecs..."},
+
+ {name: "AnyImportDecl", tag: "GenDecl"},
+ {name: "ImportDecl", tag: "GenDecl", args: "importspecs..."},
+
+ {name: "EmptyPackage", tag: "File", args: "name"},
+}
+
+type operationProto struct {
+ name string
+ value string
+ valueIndex string
+ tag string
+ example string
+ args string
+ note string
+}
+
+type operationInfo struct {
+ Example string
+ Note string
+ Args string
+ Enum uint8
+ TagName string
+ Name string
+ ValueDoc string
+ ValueIndexDoc string
+ ExtraValueKindName string
+ ValueKindName string
+ VariadicMap uint64
+ NumArgs int
+ SliceIndex int
+}
+
+const stackUnchanged = ""
+
+var fileTemplate = template.Must(template.New("operations.go").Parse(`// Code generated "gen_operations.go"; DO NOT EDIT.
+
+package gogrep
+
+import (
+ "github.com/quasilyte/gogrep/nodetag"
+)
+
+//go:generate stringer -type=operation -trimprefix=op
+type operation uint8
+
+const (
+ opInvalid operation = 0
+{{ range .Operations }}
+ // Tag: {{.TagName}}
+ {{- if .Note}}{{print "\n"}}// {{.Note}}{{end}}
+ {{- if .Args}}{{print "\n"}}// Args: {{.Args}}{{end}}
+ {{- if .Example}}{{print "\n"}}// Example: {{.Example}}{{end}}
+ {{- if .ValueDoc}}{{print "\n"}}// Value: {{.ValueDoc}}{{end}}
+ {{- if .ValueIndexDoc}}{{print "\n"}}// ValueIndex: {{.ValueIndexDoc}}{{end}}
+ op{{ .Name }} operation = {{.Enum}}
+{{ end -}}
+)
+
+type operationInfo struct {
+ Tag nodetag.Value
+ NumArgs int
+ ValueKind valueKind
+ ExtraValueKind valueKind
+ VariadicMap bitmap64
+ SliceIndex int
+}
+
+var operationInfoTable = [256]operationInfo{
+ opInvalid: {},
+
+{{ range .Operations -}}
+ op{{.Name}}: {
+ Tag: nodetag.{{.TagName}},
+ NumArgs: {{.NumArgs}},
+ ValueKind: {{.ValueKindName}},
+ ExtraValueKind: {{.ExtraValueKindName}},
+ VariadicMap: {{.VariadicMap}}, // {{printf "%b" .VariadicMap}}
+ SliceIndex: {{.SliceIndex}},
+ },
+{{ end }}
+}
+`))
+
+func main() {
+ operations := make([]operationInfo, len(opPrototypes))
+ for i, proto := range opPrototypes {
+ enum := uint8(i + 1)
+
+ tagName := proto.tag
+ if tagName == "" {
+ tagName = "Unknown"
+ }
+
+ variadicMap := uint64(0)
+ numArgs := 0
+ sliceLenIndex := -1
+ if proto.args != "" {
+ args := strings.Split(proto.args, " ")
+ numArgs = len(args)
+ for i, arg := range args {
+ isVariadic := strings.HasSuffix(arg, "...")
+ if isVariadic {
+ variadicMap |= 1 << i
+ }
+ if strings.HasSuffix(arg, "[]") {
+ sliceLenIndex = i
+ }
+ }
+ }
+
+ extraValueKindName := "emptyValue"
+ if proto.valueIndex != "" {
+ parts := strings.Split(proto.valueIndex, " | ")
+ typ := parts[0]
+ switch typ {
+ case "strings":
+ extraValueKindName = "stringValue"
+ case "ifaces":
+ extraValueKindName = "ifaceValue"
+ default:
+ panic(fmt.Sprintf("%s: unexpected %s type", proto.name, typ))
+ }
+ }
+ valueKindName := "emptyValue"
+ if proto.value != "" {
+ parts := strings.Split(proto.value, " | ")
+ typ := parts[0]
+ switch typ {
+ case "token.Token":
+ valueKindName = "tokenValue"
+ case "ast.ChanDir":
+ valueKindName = "chandirValue"
+ case "int":
+ valueKindName = "intValue"
+ default:
+ panic(fmt.Sprintf("%s: unexpected %s type", proto.name, typ))
+ }
+ }
+
+ operations[i] = operationInfo{
+ Example: proto.example,
+ Note: proto.note,
+ Args: proto.args,
+ Enum: enum,
+ TagName: tagName,
+ Name: proto.name,
+ ValueDoc: proto.value,
+ ValueIndexDoc: proto.valueIndex,
+ NumArgs: numArgs,
+ VariadicMap: variadicMap,
+ ExtraValueKindName: extraValueKindName,
+ ValueKindName: valueKindName,
+ SliceIndex: sliceLenIndex,
+ }
+ }
+
+ var buf bytes.Buffer
+ err := fileTemplate.Execute(&buf, map[string]interface{}{
+ "Operations": operations,
+ })
+ if err != nil {
+ log.Panicf("execute template: %v", err)
+ }
+ writeFile("operations.gen.go", buf.Bytes())
+}
+
+func writeFile(filename string, data []byte) {
+ pretty, err := format.Source(data)
+ if err != nil {
+ log.Panicf("gofmt: %v", err)
+ }
+ if err := ioutil.WriteFile(filename, pretty, 0666); err != nil {
+ log.Panicf("write %s: %v", filename, err)
+ }
+}
diff --git a/vendor/github.com/quasilyte/gogrep/go.mod b/vendor/github.com/quasilyte/gogrep/go.mod
new file mode 100644
index 000000000..3c76dc5e1
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/go.mod
@@ -0,0 +1,8 @@
+module github.com/quasilyte/gogrep
+
+go 1.16
+
+require (
+ github.com/go-toolsmith/astequal v1.0.1
+ github.com/google/go-cmp v0.5.6
+)
diff --git a/vendor/github.com/quasilyte/gogrep/go.sum b/vendor/github.com/quasilyte/gogrep/go.sum
new file mode 100644
index 000000000..25c3bbb3e
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/go.sum
@@ -0,0 +1,8 @@
+github.com/go-toolsmith/astequal v1.0.1 h1:JbSszi42Jiqu36Gnf363HWS9MTEAz67vTQLponh3Moc=
+github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw=
+github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
+github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/vendor/github.com/quasilyte/gogrep/gogrep.go b/vendor/github.com/quasilyte/gogrep/gogrep.go
new file mode 100644
index 000000000..313a9a251
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/gogrep.go
@@ -0,0 +1,180 @@
+package gogrep
+
+import (
+ "errors"
+ "go/ast"
+ "go/token"
+ "go/types"
+ "strings"
+
+ "github.com/quasilyte/gogrep/nodetag"
+)
+
+func IsEmptyNodeSlice(n ast.Node) bool {
+ if list, ok := n.(NodeSlice); ok {
+ return list.Len() == 0
+ }
+ return false
+}
+
+// MatchData describes a successful pattern match.
+type MatchData struct {
+ Node ast.Node
+ Capture []CapturedNode
+}
+
+type CapturedNode struct {
+ Name string
+ Node ast.Node
+}
+
+func (data MatchData) CapturedByName(name string) (ast.Node, bool) {
+ if name == "$$" {
+ return data.Node, true
+ }
+ return findNamed(data.Capture, name)
+}
+
+type PartialNode struct {
+ X ast.Node
+
+ from token.Pos
+ to token.Pos
+}
+
+func (p *PartialNode) Pos() token.Pos { return p.from }
+func (p *PartialNode) End() token.Pos { return p.to }
+
+type MatcherState struct {
+ Types *types.Info
+
+ // CapturePreset is a key-value pairs to use in the next match calls
+ // as predefined variables.
+ // For example, if the pattern is `$x = f()` and CapturePreset contains
+ // a pair with Name=x and value of `obj.x`, then the above mentioned
+ // pattern will only match `obj.x = f()` statements.
+ //
+ // If nil, the default behavior will be used. A first syntax element
+ // matching the matcher var will be captured.
+ CapturePreset []CapturedNode
+
+ // node values recorded by name, excluding "_" (used only by the
+ // actual matching phase)
+ capture []CapturedNode
+
+ pc int
+
+ partial PartialNode
+}
+
+func NewMatcherState() MatcherState {
+ return MatcherState{
+ capture: make([]CapturedNode, 0, 8),
+ }
+}
+
+type Pattern struct {
+ m *matcher
+}
+
+type PatternInfo struct {
+ Vars map[string]struct{}
+}
+
+func (p *Pattern) NodeTag() nodetag.Value {
+ return operationInfoTable[p.m.prog.insts[0].op].Tag
+}
+
+// MatchNode calls cb if n matches a pattern.
+func (p *Pattern) MatchNode(state *MatcherState, n ast.Node, cb func(MatchData)) {
+ p.m.MatchNode(state, n, cb)
+}
+
+// Clone creates a pattern copy.
+func (p *Pattern) Clone() *Pattern {
+ clone := *p
+ clone.m = &matcher{}
+ *clone.m = *p.m
+ return &clone
+}
+
+type CompileConfig struct {
+ Fset *token.FileSet
+
+ // Src is a gogrep pattern expression string.
+ Src string
+
+ // When strict is false, gogrep may consider 0xA and 10 to be identical.
+ // If true, a compiled pattern will require a full syntax match.
+ Strict bool
+
+ // WithTypes controls whether gogrep would have types.Info during the pattern execution.
+ // If set to true, it will compile a pattern to a potentially more precise form, where
+ // fmt.Printf maps to the stdlib function call but not Printf method call on some
+ // random fmt variable.
+ WithTypes bool
+
+ // Imports specifies packages that should be recognized for the type-aware matching.
+ // It maps a package name to a package path.
+ // Only used if WithTypes is true.
+ Imports map[string]string
+}
+
+func Compile(config CompileConfig) (*Pattern, PatternInfo, error) {
+ if strings.HasPrefix(config.Src, "import $") {
+ return compileImportPattern(config)
+ }
+ info := newPatternInfo()
+ n, err := parseExpr(config.Fset, config.Src)
+ if err != nil {
+ return nil, info, err
+ }
+ if n == nil {
+ return nil, info, errors.New("invalid pattern syntax")
+ }
+ var c compiler
+ c.config = config
+ prog, err := c.Compile(n, &info)
+ if err != nil {
+ return nil, info, err
+ }
+ m := newMatcher(prog)
+ return &Pattern{m: m}, info, nil
+}
+
+func Walk(root ast.Node, fn func(n ast.Node) bool) {
+ switch root := root.(type) {
+ case ExprSlice:
+ for _, e := range root {
+ ast.Inspect(e, fn)
+ }
+ case stmtSlice:
+ for _, e := range root {
+ ast.Inspect(e, fn)
+ }
+ case fieldSlice:
+ for _, e := range root {
+ ast.Inspect(e, fn)
+ }
+ case identSlice:
+ for _, e := range root {
+ ast.Inspect(e, fn)
+ }
+ case specSlice:
+ for _, e := range root {
+ ast.Inspect(e, fn)
+ }
+ case declSlice:
+ for _, e := range root {
+ ast.Inspect(e, fn)
+ }
+ default:
+ ast.Inspect(root, fn)
+ }
+}
+
+func newPatternInfo() PatternInfo {
+ return PatternInfo{
+ Vars: make(map[string]struct{}),
+ }
+}
diff --git a/vendor/github.com/quasilyte/gogrep/instructions.go b/vendor/github.com/quasilyte/gogrep/instructions.go
new file mode 100644
index 000000000..9f4f72d88
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/instructions.go
@@ -0,0 +1,116 @@
+package gogrep
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "strings"
+)
+
+type bitmap64 uint64
+
+func (m bitmap64) IsSet(pos int) bool {
+ return m&(1<<pos) != 0
+}
+
+type valueKind uint8
+
+const (
+ emptyValue valueKind = iota
+ stringValue // Extra values only; value is stored in program.strings
+ ifaceValue // Extra values only; value is stored in program.ifaces
+ tokenValue // token.Token
+ chandirValue // ast.CharDir
+ intValue // int
+)
+
+type program struct {
+ insts []instruction
+ strings []string
+ ifaces []interface{}
+}
+
+func formatProgram(p *program) []string {
+ var parts []string
+ insts := p.insts
+
+ nextInst := func() instruction {
+ inst := insts[0]
+ insts = insts[1:]
+ return inst
+ }
+ peekOp := func() operation {
+ return insts[0].op
+ }
+
+ var walk func(int)
+ walk = func(depth int) {
+ if len(insts) == 0 {
+ return
+ }
+ inst := nextInst()
+
+ part := strings.Repeat(" • ", depth) + formatInstruction(p, inst)
+ parts = append(parts, part)
+
+ info := operationInfoTable[inst.op]
+ for i := 0; i < info.NumArgs; i++ {
+ if i == info.SliceIndex {
+ for j := 0; j < int(inst.value); j++ {
+ walk(depth + 1)
+ }
+ continue
+ }
+ if !info.VariadicMap.IsSet(i) {
+ walk(depth + 1)
+ continue
+ }
+ for {
+ isEnd := peekOp() == opEnd
+ walk(depth + 1)
+ if isEnd {
+ break
+ }
+ }
+ }
+ }
+
+ walk(0)
+ return parts
+}
+
+func formatInstruction(p *program, inst instruction) string {
+ parts := []string{inst.op.String()}
+
+ info := operationInfoTable[inst.op]
+
+ switch info.ValueKind {
+ case chandirValue:
+ dir := ast.ChanDir(inst.value)
+ if dir&ast.SEND != 0 {
+ parts = append(parts, "send")
+ }
+ if dir&ast.RECV != 0 {
+ parts = append(parts, "recv")
+ }
+ case tokenValue:
+ parts = append(parts, token.Token(inst.value).String())
+ case intValue:
+ parts = append(parts, fmt.Sprint(inst.value))
+ }
+
+ switch info.ExtraValueKind {
+ case ifaceValue:
+ parts = append(parts, fmt.Sprintf("%#v", p.ifaces[inst.valueIndex]))
+ case stringValue:
+ parts = append(parts, p.strings[inst.valueIndex])
+ }
+
+ return strings.Join(parts, " ")
+}
+
+type instruction struct {
+ op operation
+ value uint8
+ valueIndex uint8
+}
diff --git a/vendor/github.com/quasilyte/gogrep/internal/stdinfo/stdinfo.go b/vendor/github.com/quasilyte/gogrep/internal/stdinfo/stdinfo.go
new file mode 100644
index 000000000..f00d66d46
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/internal/stdinfo/stdinfo.go
@@ -0,0 +1,151 @@
+package stdinfo
+
+var Packages = map[string]string{
+ "adler32": "hash/adler32",
+ "aes": "crypto/aes",
+ "ascii85": "encoding/ascii85",
+ "asn1": "encoding/asn1",
+ "ast": "go/ast",
+ "atomic": "sync/atomic",
+ "base32": "encoding/base32",
+ "base64": "encoding/base64",
+ "big": "math/big",
+ "binary": "encoding/binary",
+ "bits": "math/bits",
+ "bufio": "bufio",
+ "build": "go/build",
+ "bytes": "bytes",
+ "bzip2": "compress/bzip2",
+ "cgi": "net/http/cgi",
+ "cgo": "runtime/cgo",
+ "cipher": "crypto/cipher",
+ "cmplx": "math/cmplx",
+ "color": "image/color",
+ "constant": "go/constant",
+ "constraint": "go/build/constraint",
+ "context": "context",
+ "cookiejar": "net/http/cookiejar",
+ "crc32": "hash/crc32",
+ "crc64": "hash/crc64",
+ "crypto": "crypto",
+ "csv": "encoding/csv",
+ "debug": "runtime/debug",
+ "des": "crypto/des",
+ "doc": "go/doc",
+ "draw": "image/draw",
+ "driver": "database/sql/driver",
+ "dsa": "crypto/dsa",
+ "dwarf": "debug/dwarf",
+ "ecdsa": "crypto/ecdsa",
+ "ed25519": "crypto/ed25519",
+ "elf": "debug/elf",
+ "elliptic": "crypto/elliptic",
+ "embed": "embed",
+ "encoding": "encoding",
+ "errors": "errors",
+ "exec": "os/exec",
+ "expvar": "expvar",
+ "fcgi": "net/http/fcgi",
+ "filepath": "path/filepath",
+ "flag": "flag",
+ "flate": "compress/flate",
+ "fmt": "fmt",
+ "fnv": "hash/fnv",
+ "format": "go/format",
+ "fs": "io/fs",
+ "fstest": "testing/fstest",
+ "gif": "image/gif",
+ "gob": "encoding/gob",
+ "gosym": "debug/gosym",
+ "gzip": "compress/gzip",
+ "hash": "hash",
+ "heap": "container/heap",
+ "hex": "encoding/hex",
+ "hmac": "crypto/hmac",
+ "html": "html",
+ "http": "net/http",
+ "httptest": "net/http/httptest",
+ "httptrace": "net/http/httptrace",
+ "httputil": "net/http/httputil",
+ "image": "image",
+ "importer": "go/importer",
+ "io": "io",
+ "iotest": "testing/iotest",
+ "ioutil": "io/ioutil",
+ "jpeg": "image/jpeg",
+ "json": "encoding/json",
+ "jsonrpc": "net/rpc/jsonrpc",
+ "list": "container/list",
+ "log": "log",
+ "lzw": "compress/lzw",
+ "macho": "debug/macho",
+ "mail": "net/mail",
+ "maphash": "hash/maphash",
+ "math": "math",
+ "md5": "crypto/md5",
+ "metrics": "runtime/metrics",
+ "mime": "mime",
+ "multipart": "mime/multipart",
+ "net": "net",
+ "os": "os",
+ "palette": "image/color/palette",
+ "parse": "text/template/parse",
+ "parser": "go/parser",
+ "path": "path",
+ "pe": "debug/pe",
+ "pem": "encoding/pem",
+ "pkix": "crypto/x509/pkix",
+ "plan9obj": "debug/plan9obj",
+ "plugin": "plugin",
+ "png": "image/png",
+ "pprof": "runtime/pprof",
+ "printer": "go/printer",
+ "quick": "testing/quick",
+ "quotedprintable": "mime/quotedprintable",
+ "race": "runtime/race",
+ "rand": "math/rand",
+ "rc4": "crypto/rc4",
+ "reflect": "reflect",
+ "regexp": "regexp",
+ "ring": "container/ring",
+ "rpc": "net/rpc",
+ "rsa": "crypto/rsa",
+ "runtime": "runtime",
+ "scanner": "text/scanner",
+ "sha1": "crypto/sha1",
+ "sha256": "crypto/sha256",
+ "sha512": "crypto/sha512",
+ "signal": "os/signal",
+ "smtp": "net/smtp",
+ "sort": "sort",
+ "sql": "database/sql",
+ "strconv": "strconv",
+ "strings": "strings",
+ "subtle": "crypto/subtle",
+ "suffixarray": "index/suffixarray",
+ "sync": "sync",
+ "syntax": "regexp/syntax",
+ "syscall": "syscall",
+ "syslog": "log/syslog",
+ "tabwriter": "text/tabwriter",
+ "tar": "archive/tar",
+ "template": "text/template",
+ "testing": "testing",
+ "textproto": "net/textproto",
+ "time": "time",
+ "tls": "crypto/tls",
+ "token": "go/token",
+ "trace": "runtime/trace",
+ "types": "go/types",
+ "tzdata": "time/tzdata",
+ "unicode": "unicode",
+ "unsafe": "unsafe",
+ "url": "net/url",
+ "user": "os/user",
+ "utf16": "unicode/utf16",
+ "utf8": "unicode/utf8",
+ "x509": "crypto/x509",
+ "xml": "encoding/xml",
+ "zip": "archive/zip",
+ "zlib": "compress/zlib",
+}
diff --git a/vendor/github.com/quasilyte/gogrep/match.go b/vendor/github.com/quasilyte/gogrep/match.go
new file mode 100644
index 000000000..d927beff3
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/match.go
@@ -0,0 +1,937 @@
+package gogrep
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/types"
+ "strconv"
+
+ "github.com/go-toolsmith/astequal"
+)
+
+type matcher struct {
+ prog *program
+
+ insts []instruction
+}
+
+func newMatcher(prog *program) *matcher {
+ return &matcher{
+ prog: prog,
+ insts: prog.insts,
+ }
+}
+
+func (m *matcher) nextInst(state *MatcherState) instruction {
+ inst := m.insts[state.pc]
+ state.pc++
+ return inst
+}
+
+func (m *matcher) stringValue(inst instruction) string {
+ return m.prog.strings[inst.valueIndex]
+}
+
+func (m *matcher) ifaceValue(inst instruction) interface{} {
+ return m.prog.ifaces[inst.valueIndex]
+}
+
+func (m *matcher) resetCapture(state *MatcherState) {
+ state.capture = state.capture[:0]
+ if state.CapturePreset != nil {
+ state.capture = append(state.capture, state.CapturePreset...)
+ }
+}
+
+func (m *matcher) MatchNode(state *MatcherState, n ast.Node, accept func(MatchData)) {
+ state.pc = 0
+ inst := m.nextInst(state)
+ switch inst.op {
+ case opMultiStmt:
+ switch n := n.(type) {
+ case *ast.BlockStmt:
+ m.walkStmtSlice(state, n.List, accept)
+ case *ast.CaseClause:
+ m.walkStmtSlice(state, n.Body, accept)
+ case *ast.CommClause:
+ m.walkStmtSlice(state, n.Body, accept)
+ }
+ case opMultiExpr:
+ switch n := n.(type) {
+ case *ast.CallExpr:
+ m.walkExprSlice(state, n.Args, accept)
+ case *ast.CompositeLit:
+ m.walkExprSlice(state, n.Elts, accept)
+ case *ast.ReturnStmt:
+ m.walkExprSlice(state, n.Results, accept)
+ }
+ case opMultiDecl:
+ if n, ok := n.(*ast.File); ok {
+ m.walkDeclSlice(state, n.Decls, accept)
+ }
+ case opRangeClause:
+ m.matchRangeClause(state, n, accept)
+ case opRangeHeader:
+ m.matchRangeHeader(state, n, accept)
+ case opRangeKeyHeader:
+ m.matchRangeKeyHeader(state, inst, n, accept)
+ case opRangeKeyValueHeader:
+ m.matchRangeKeyValueHeader(state, inst, n, accept)
+ default:
+ m.resetCapture(state)
+ if m.matchNodeWithInst(state, inst, n) {
+ accept(MatchData{
+ Capture: state.capture,
+ Node: n,
+ })
+ }
+ }
+}
+
+func (m *matcher) walkDeclSlice(state *MatcherState, decls []ast.Decl, accept func(MatchData)) {
+ m.walkNodeSlice(state, declSlice(decls), accept)
+}
+
+func (m *matcher) walkExprSlice(state *MatcherState, exprs []ast.Expr, accept func(MatchData)) {
+ m.walkNodeSlice(state, ExprSlice(exprs), accept)
+}
+
+func (m *matcher) walkStmtSlice(state *MatcherState, stmts []ast.Stmt, accept func(MatchData)) {
+ m.walkNodeSlice(state, stmtSlice(stmts), accept)
+}
+
+func (m *matcher) walkNodeSlice(state *MatcherState, nodes NodeSlice, accept func(MatchData)) {
+ sliceLen := nodes.Len()
+ from := 0
+ for {
+ state.pc = 1 // FIXME: this is a kludge
+ m.resetCapture(state)
+ matched, offset := m.matchNodeList(state, nodes.slice(from, sliceLen), true)
+ if matched == nil {
+ break
+ }
+ accept(MatchData{
+ Capture: state.capture,
+ Node: matched,
+ })
+ from += offset - 1
+ if from >= sliceLen {
+ break
+ }
+ }
+}
+
+func (m *matcher) matchNamed(state *MatcherState, name string, n ast.Node) bool {
+ prev, ok := findNamed(state.capture, name)
+ if !ok {
+ // First occurrence, record value.
+ state.capture = append(state.capture, CapturedNode{Name: name, Node: n})
+ return true
+ }
+
+ return equalNodes(prev, n)
+}
+
+func (m *matcher) matchNamedField(state *MatcherState, name string, n ast.Node) bool {
+ prev, ok := findNamed(state.capture, name)
+ if !ok {
+ // First occurrence, record value.
+ unwrapped := m.unwrapNode(n)
+ state.capture = append(state.capture, CapturedNode{Name: name, Node: unwrapped})
+ return true
+ }
+ n = m.unwrapNode(n)
+ return equalNodes(prev, n)
+}
+
+func (m *matcher) unwrapNode(x ast.Node) ast.Node {
+ switch x := x.(type) {
+ case *ast.Field:
+ if len(x.Names) == 0 {
+ return x.Type
+ }
+ case *ast.FieldList:
+ if x != nil && len(x.List) == 1 && len(x.List[0].Names) == 0 {
+ return x.List[0].Type
+ }
+ }
+ return x
+}
+
+func (m *matcher) matchNodeWithInst(state *MatcherState, inst instruction, n ast.Node) bool {
+ switch inst.op {
+ case opNode:
+ return n != nil
+ case opOptNode:
+ return true
+
+ case opNamedNode:
+ return n != nil && m.matchNamed(state, m.stringValue(inst), n)
+ case opNamedOptNode:
+ return m.matchNamed(state, m.stringValue(inst), n)
+
+ case opFieldNode:
+ n, ok := n.(*ast.FieldList)
+ return ok && n != nil && len(n.List) == 1 && len(n.List[0].Names) == 0
+ case opNamedFieldNode:
+ return n != nil && m.matchNamedField(state, m.stringValue(inst), n)
+
+ case opBasicLit:
+ n, ok := n.(*ast.BasicLit)
+ return ok && m.ifaceValue(inst) == literalValue(n)
+
+ case opStrictIntLit:
+ n, ok := n.(*ast.BasicLit)
+ return ok && n.Kind == token.INT && m.stringValue(inst) == n.Value
+ case opStrictFloatLit:
+ n, ok := n.(*ast.BasicLit)
+ return ok && n.Kind == token.FLOAT && m.stringValue(inst) == n.Value
+ case opStrictCharLit:
+ n, ok := n.(*ast.BasicLit)
+ return ok && n.Kind == token.CHAR && m.stringValue(inst) == n.Value
+ case opStrictStringLit:
+ n, ok := n.(*ast.BasicLit)
+ return ok && n.Kind == token.STRING && m.stringValue(inst) == n.Value
+ case opStrictComplexLit:
+ n, ok := n.(*ast.BasicLit)
+ return ok && n.Kind == token.IMAG && m.stringValue(inst) == n.Value
+
+ case opIdent:
+ n, ok := n.(*ast.Ident)
+ return ok && m.stringValue(inst) == n.Name
+
+ case opPkg:
+ n, ok := n.(*ast.Ident)
+ if !ok {
+ return false
+ }
+ obj := state.Types.ObjectOf(n)
+ if obj == nil {
+ return false
+ }
+ pkgName, ok := obj.(*types.PkgName)
+ return ok && pkgName.Imported().Path() == m.stringValue(inst)
+
+ case opBinaryExpr:
+ n, ok := n.(*ast.BinaryExpr)
+ return ok && n.Op == token.Token(inst.value) &&
+ m.matchNode(state, n.X) && m.matchNode(state, n.Y)
+
+ case opUnaryExpr:
+ n, ok := n.(*ast.UnaryExpr)
+ return ok && n.Op == token.Token(inst.value) && m.matchNode(state, n.X)
+
+ case opStarExpr:
+ n, ok := n.(*ast.StarExpr)
+ return ok && m.matchNode(state, n.X)
+
+ case opVariadicCallExpr:
+ n, ok := n.(*ast.CallExpr)
+ return ok && n.Ellipsis.IsValid() && m.matchNode(state, n.Fun) && m.matchArgList(state, n.Args)
+ case opNonVariadicCallExpr:
+ n, ok := n.(*ast.CallExpr)
+ return ok && !n.Ellipsis.IsValid() && m.matchNode(state, n.Fun) && m.matchArgList(state, n.Args)
+ case opCallExpr:
+ n, ok := n.(*ast.CallExpr)
+ return ok && m.matchNode(state, n.Fun) && m.matchArgList(state, n.Args)
+
+ case opSimpleSelectorExpr:
+ n, ok := n.(*ast.SelectorExpr)
+ return ok && m.stringValue(inst) == n.Sel.Name && m.matchNode(state, n.X)
+ case opSelectorExpr:
+ n, ok := n.(*ast.SelectorExpr)
+ return ok && m.matchNode(state, n.Sel) && m.matchNode(state, n.X)
+
+ case opTypeAssertExpr:
+ n, ok := n.(*ast.TypeAssertExpr)
+ return ok && m.matchNode(state, n.X) && m.matchNode(state, n.Type)
+ case opTypeSwitchAssertExpr:
+ n, ok := n.(*ast.TypeAssertExpr)
+ return ok && n.Type == nil && m.matchNode(state, n.X)
+
+ case opSliceExpr:
+ n, ok := n.(*ast.SliceExpr)
+ return ok && n.Low == nil && n.High == nil && m.matchNode(state, n.X)
+ case opSliceFromExpr:
+ n, ok := n.(*ast.SliceExpr)
+ return ok && n.High == nil && !n.Slice3 &&
+ m.matchNode(state, n.X) && m.matchNode(state, n.Low)
+ case opSliceToExpr:
+ n, ok := n.(*ast.SliceExpr)
+ return ok && n.Low == nil && !n.Slice3 &&
+ m.matchNode(state, n.X) && m.matchNode(state, n.High)
+ case opSliceFromToExpr:
+ n, ok := n.(*ast.SliceExpr)
+ return ok && !n.Slice3 &&
+ m.matchNode(state, n.X) && m.matchNode(state, n.Low) && m.matchNode(state, n.High)
+ case opSliceToCapExpr:
+ n, ok := n.(*ast.SliceExpr)
+ return ok && n.Low == nil &&
+ m.matchNode(state, n.X) && m.matchNode(state, n.High) && m.matchNode(state, n.Max)
+ case opSliceFromToCapExpr:
+ n, ok := n.(*ast.SliceExpr)
+ return ok && m.matchNode(state, n.X) && m.matchNode(state, n.Low) && m.matchNode(state, n.High) && m.matchNode(state, n.Max)
+
+ case opIndexExpr:
+ n, ok := n.(*ast.IndexExpr)
+ return ok && m.matchNode(state, n.X) && m.matchNode(state, n.Index)
+
+ case opKeyValueExpr:
+ n, ok := n.(*ast.KeyValueExpr)
+ return ok && m.matchNode(state, n.Key) && m.matchNode(state, n.Value)
+
+ case opParenExpr:
+ n, ok := n.(*ast.ParenExpr)
+ return ok && m.matchNode(state, n.X)
+
+ case opEllipsis:
+ n, ok := n.(*ast.Ellipsis)
+ return ok && n.Elt == nil
+ case opTypedEllipsis:
+ n, ok := n.(*ast.Ellipsis)
+ return ok && n.Elt != nil && m.matchNode(state, n.Elt)
+
+ case opSliceType:
+ n, ok := n.(*ast.ArrayType)
+ return ok && n.Len == nil && m.matchNode(state, n.Elt)
+ case opArrayType:
+ n, ok := n.(*ast.ArrayType)
+ return ok && n.Len != nil && m.matchNode(state, n.Len) && m.matchNode(state, n.Elt)
+ case opMapType:
+ n, ok := n.(*ast.MapType)
+ return ok && m.matchNode(state, n.Key) && m.matchNode(state, n.Value)
+ case opChanType:
+ n, ok := n.(*ast.ChanType)
+ return ok && ast.ChanDir(inst.value) == n.Dir && m.matchNode(state, n.Value)
+ case opVoidFuncType:
+ n, ok := n.(*ast.FuncType)
+ return ok && n.Results == nil && m.matchNode(state, n.Params)
+ case opFuncType:
+ n, ok := n.(*ast.FuncType)
+ return ok && m.matchNode(state, n.Params) && m.matchNode(state, n.Results)
+ case opStructType:
+ n, ok := n.(*ast.StructType)
+ return ok && m.matchNode(state, n.Fields)
+ case opInterfaceType:
+ n, ok := n.(*ast.InterfaceType)
+ return ok && m.matchNode(state, n.Methods)
+
+ case opCompositeLit:
+ n, ok := n.(*ast.CompositeLit)
+ return ok && n.Type == nil && m.matchExprSlice(state, n.Elts)
+ case opTypedCompositeLit:
+ n, ok := n.(*ast.CompositeLit)
+ return ok && n.Type != nil && m.matchNode(state, n.Type) && m.matchExprSlice(state, n.Elts)
+
+ case opUnnamedField:
+ n, ok := n.(*ast.Field)
+ return ok && len(n.Names) == 0 && m.matchNode(state, n.Type)
+ case opSimpleField:
+ n, ok := n.(*ast.Field)
+ return ok && len(n.Names) == 1 && m.stringValue(inst) == n.Names[0].Name && m.matchNode(state, n.Type)
+ case opField:
+ n, ok := n.(*ast.Field)
+ return ok && len(n.Names) == 1 && m.matchNode(state, n.Names[0]) && m.matchNode(state, n.Type)
+ case opMultiField:
+ n, ok := n.(*ast.Field)
+ return ok && len(n.Names) >= 2 && m.matchIdentSlice(state, n.Names) && m.matchNode(state, n.Type)
+ case opFieldList:
+ // FieldList could be nil in places like function return types.
+ n, ok := n.(*ast.FieldList)
+ return ok && n != nil && m.matchFieldSlice(state, n.List)
+
+ case opFuncLit:
+ n, ok := n.(*ast.FuncLit)
+ return ok && m.matchNode(state, n.Type) && m.matchNode(state, n.Body)
+
+ case opAssignStmt:
+ n, ok := n.(*ast.AssignStmt)
+ return ok && token.Token(inst.value) == n.Tok &&
+ len(n.Lhs) == 1 && m.matchNode(state, n.Lhs[0]) &&
+ len(n.Rhs) == 1 && m.matchNode(state, n.Rhs[0])
+ case opMultiAssignStmt:
+ n, ok := n.(*ast.AssignStmt)
+ return ok && token.Token(inst.value) == n.Tok &&
+ m.matchExprSlice(state, n.Lhs) && m.matchExprSlice(state, n.Rhs)
+
+ case opExprStmt:
+ n, ok := n.(*ast.ExprStmt)
+ return ok && m.matchNode(state, n.X)
+
+ case opGoStmt:
+ n, ok := n.(*ast.GoStmt)
+ return ok && m.matchNode(state, n.Call)
+ case opDeferStmt:
+ n, ok := n.(*ast.DeferStmt)
+ return ok && m.matchNode(state, n.Call)
+ case opSendStmt:
+ n, ok := n.(*ast.SendStmt)
+ return ok && m.matchNode(state, n.Chan) && m.matchNode(state, n.Value)
+
+ case opBlockStmt:
+ n, ok := n.(*ast.BlockStmt)
+ return ok && m.matchStmtSlice(state, n.List)
+
+ case opIfStmt:
+ n, ok := n.(*ast.IfStmt)
+ return ok && n.Init == nil && n.Else == nil &&
+ m.matchNode(state, n.Cond) && m.matchNode(state, n.Body)
+ case opIfElseStmt:
+ n, ok := n.(*ast.IfStmt)
+ return ok && n.Init == nil && n.Else != nil &&
+ m.matchNode(state, n.Cond) && m.matchNode(state, n.Body) && m.matchNode(state, n.Else)
+ case opIfInitStmt:
+ n, ok := n.(*ast.IfStmt)
+ return ok && n.Else == nil &&
+ m.matchNode(state, n.Init) && m.matchNode(state, n.Cond) && m.matchNode(state, n.Body)
+ case opIfInitElseStmt:
+ n, ok := n.(*ast.IfStmt)
+ return ok && n.Else != nil &&
+ m.matchNode(state, n.Init) && m.matchNode(state, n.Cond) && m.matchNode(state, n.Body) && m.matchNode(state, n.Else)
+
+ case opIfNamedOptStmt:
+ n, ok := n.(*ast.IfStmt)
+ return ok && n.Else == nil && m.matchNode(state, n.Body) &&
+ m.matchNamed(state, m.stringValue(inst), toStmtSlice(n.Cond, n.Init))
+ case opIfNamedOptElseStmt:
+ n, ok := n.(*ast.IfStmt)
+ return ok && n.Else != nil && m.matchNode(state, n.Body) && m.matchNode(state, n.Else) &&
+ m.matchNamed(state, m.stringValue(inst), toStmtSlice(n.Cond, n.Init))
+
+ case opCaseClause:
+ n, ok := n.(*ast.CaseClause)
+ return ok && n.List != nil && m.matchExprSlice(state, n.List) && m.matchStmtSlice(state, n.Body)
+ case opDefaultCaseClause:
+ n, ok := n.(*ast.CaseClause)
+ return ok && n.List == nil && m.matchStmtSlice(state, n.Body)
+
+ case opSwitchStmt:
+ n, ok := n.(*ast.SwitchStmt)
+ return ok && n.Init == nil && n.Tag == nil && m.matchStmtSlice(state, n.Body.List)
+ case opSwitchTagStmt:
+ n, ok := n.(*ast.SwitchStmt)
+ return ok && n.Init == nil && m.matchNode(state, n.Tag) && m.matchStmtSlice(state, n.Body.List)
+ case opSwitchInitStmt:
+ n, ok := n.(*ast.SwitchStmt)
+ return ok && n.Tag == nil && m.matchNode(state, n.Init) && m.matchStmtSlice(state, n.Body.List)
+ case opSwitchInitTagStmt:
+ n, ok := n.(*ast.SwitchStmt)
+ return ok && m.matchNode(state, n.Init) && m.matchNode(state, n.Tag) && m.matchStmtSlice(state, n.Body.List)
+
+ case opTypeSwitchStmt:
+ n, ok := n.(*ast.TypeSwitchStmt)
+ return ok && n.Init == nil && m.matchNode(state, n.Assign) && m.matchStmtSlice(state, n.Body.List)
+ case opTypeSwitchInitStmt:
+ n, ok := n.(*ast.TypeSwitchStmt)
+ return ok && m.matchNode(state, n.Init) &&
+ m.matchNode(state, n.Assign) && m.matchStmtSlice(state, n.Body.List)
+
+ case opCommClause:
+ n, ok := n.(*ast.CommClause)
+ return ok && n.Comm != nil && m.matchNode(state, n.Comm) && m.matchStmtSlice(state, n.Body)
+ case opDefaultCommClause:
+ n, ok := n.(*ast.CommClause)
+ return ok && n.Comm == nil && m.matchStmtSlice(state, n.Body)
+
+ case opSelectStmt:
+ n, ok := n.(*ast.SelectStmt)
+ return ok && m.matchStmtSlice(state, n.Body.List)
+
+ case opRangeStmt:
+ n, ok := n.(*ast.RangeStmt)
+ return ok && n.Key == nil && n.Value == nil && m.matchNode(state, n.X) && m.matchNode(state, n.Body)
+ case opRangeKeyStmt:
+ n, ok := n.(*ast.RangeStmt)
+ return ok && n.Key != nil && n.Value == nil && token.Token(inst.value) == n.Tok &&
+ m.matchNode(state, n.Key) && m.matchNode(state, n.X) && m.matchNode(state, n.Body)
+ case opRangeKeyValueStmt:
+ n, ok := n.(*ast.RangeStmt)
+ return ok && n.Key != nil && n.Value != nil && token.Token(inst.value) == n.Tok &&
+ m.matchNode(state, n.Key) && m.matchNode(state, n.Value) && m.matchNode(state, n.X) && m.matchNode(state, n.Body)
+
+ case opForStmt:
+ n, ok := n.(*ast.ForStmt)
+ return ok && n.Init == nil && n.Cond == nil && n.Post == nil &&
+ m.matchNode(state, n.Body)
+ case opForPostStmt:
+ n, ok := n.(*ast.ForStmt)
+ return ok && n.Init == nil && n.Cond == nil && n.Post != nil &&
+ m.matchNode(state, n.Post) && m.matchNode(state, n.Body)
+ case opForCondStmt:
+ n, ok := n.(*ast.ForStmt)
+ return ok && n.Init == nil && n.Cond != nil && n.Post == nil &&
+ m.matchNode(state, n.Cond) && m.matchNode(state, n.Body)
+ case opForCondPostStmt:
+ n, ok := n.(*ast.ForStmt)
+ return ok && n.Init == nil && n.Cond != nil && n.Post != nil &&
+ m.matchNode(state, n.Cond) && m.matchNode(state, n.Post) && m.matchNode(state, n.Body)
+ case opForInitStmt:
+ n, ok := n.(*ast.ForStmt)
+ return ok && n.Init != nil && n.Cond == nil && n.Post == nil &&
+ m.matchNode(state, n.Init) && m.matchNode(state, n.Body)
+ case opForInitPostStmt:
+ n, ok := n.(*ast.ForStmt)
+ return ok && n.Init != nil && n.Cond == nil && n.Post != nil &&
+ m.matchNode(state, n.Init) && m.matchNode(state, n.Post) && m.matchNode(state, n.Body)
+ case opForInitCondStmt:
+ n, ok := n.(*ast.ForStmt)
+ return ok && n.Init != nil && n.Cond != nil && n.Post == nil &&
+ m.matchNode(state, n.Init) && m.matchNode(state, n.Cond) && m.matchNode(state, n.Body)
+ case opForInitCondPostStmt:
+ n, ok := n.(*ast.ForStmt)
+ return ok && m.matchNode(state, n.Init) && m.matchNode(state, n.Cond) && m.matchNode(state, n.Post) && m.matchNode(state, n.Body)
+
+ case opIncDecStmt:
+ n, ok := n.(*ast.IncDecStmt)
+ return ok && token.Token(inst.value) == n.Tok && m.matchNode(state, n.X)
+
+ case opReturnStmt:
+ n, ok := n.(*ast.ReturnStmt)
+ return ok && m.matchExprSlice(state, n.Results)
+
+ case opLabeledStmt:
+ n, ok := n.(*ast.LabeledStmt)
+ return ok && m.matchNode(state, n.Label) && m.matchNode(state, n.Stmt)
+ case opSimpleLabeledStmt:
+ n, ok := n.(*ast.LabeledStmt)
+ return ok && m.stringValue(inst) == n.Label.Name && m.matchNode(state, n.Stmt)
+
+ case opLabeledBranchStmt:
+ n, ok := n.(*ast.BranchStmt)
+ return ok && n.Label != nil && token.Token(inst.value) == n.Tok && m.matchNode(state, n.Label)
+ case opSimpleLabeledBranchStmt:
+ n, ok := n.(*ast.BranchStmt)
+ return ok && n.Label != nil && m.stringValue(inst) == n.Label.Name && token.Token(inst.value) == n.Tok
+ case opBranchStmt:
+ n, ok := n.(*ast.BranchStmt)
+ return ok && n.Label == nil && token.Token(inst.value) == n.Tok
+
+ case opEmptyStmt:
+ _, ok := n.(*ast.EmptyStmt)
+ return ok
+
+ case opFuncDecl:
+ n, ok := n.(*ast.FuncDecl)
+ return ok && n.Recv == nil && n.Body != nil &&
+ m.matchNode(state, n.Name) && m.matchNode(state, n.Type) && m.matchNode(state, n.Body)
+ case opFuncProtoDecl:
+ n, ok := n.(*ast.FuncDecl)
+ return ok && n.Recv == nil && n.Body == nil &&
+ m.matchNode(state, n.Name) && m.matchNode(state, n.Type)
+ case opMethodDecl:
+ n, ok := n.(*ast.FuncDecl)
+ return ok && n.Recv != nil && n.Body != nil &&
+ m.matchNode(state, n.Recv) && m.matchNode(state, n.Name) && m.matchNode(state, n.Type) && m.matchNode(state, n.Body)
+ case opMethodProtoDecl:
+ n, ok := n.(*ast.FuncDecl)
+ return ok && n.Recv != nil && n.Body == nil &&
+ m.matchNode(state, n.Recv) && m.matchNode(state, n.Name) && m.matchNode(state, n.Type)
+
+ case opValueSpec:
+ n, ok := n.(*ast.ValueSpec)
+ return ok && len(n.Values) == 0 && n.Type == nil &&
+ len(n.Names) == 1 && m.matchNode(state, n.Names[0])
+ case opValueInitSpec:
+ n, ok := n.(*ast.ValueSpec)
+ return ok && len(n.Values) != 0 && n.Type == nil &&
+ m.matchIdentSlice(state, n.Names) && m.matchExprSlice(state, n.Values)
+ case opTypedValueSpec:
+ n, ok := n.(*ast.ValueSpec)
+ return ok && len(n.Values) == 0 && n.Type != nil &&
+ m.matchIdentSlice(state, n.Names) && m.matchNode(state, n.Type)
+ case opTypedValueInitSpec:
+ n, ok := n.(*ast.ValueSpec)
+ return ok && len(n.Values) != 0 &&
+ m.matchIdentSlice(state, n.Names) && m.matchNode(state, n.Type) && m.matchExprSlice(state, n.Values)
+
+ case opTypeSpec:
+ n, ok := n.(*ast.TypeSpec)
+ return ok && !n.Assign.IsValid() && m.matchNode(state, n.Name) && m.matchNode(state, n.Type)
+ case opTypeAliasSpec:
+ n, ok := n.(*ast.TypeSpec)
+ return ok && n.Assign.IsValid() && m.matchNode(state, n.Name) && m.matchNode(state, n.Type)
+
+ case opDeclStmt:
+ n, ok := n.(*ast.DeclStmt)
+ return ok && m.matchNode(state, n.Decl)
+
+ case opConstDecl:
+ n, ok := n.(*ast.GenDecl)
+ return ok && n.Tok == token.CONST && m.matchSpecSlice(state, n.Specs)
+ case opVarDecl:
+ n, ok := n.(*ast.GenDecl)
+ return ok && n.Tok == token.VAR && m.matchSpecSlice(state, n.Specs)
+ case opTypeDecl:
+ n, ok := n.(*ast.GenDecl)
+ return ok && n.Tok == token.TYPE && m.matchSpecSlice(state, n.Specs)
+ case opAnyImportDecl:
+ n, ok := n.(*ast.GenDecl)
+ return ok && n.Tok == token.IMPORT
+ case opImportDecl:
+ n, ok := n.(*ast.GenDecl)
+ return ok && n.Tok == token.IMPORT && m.matchSpecSlice(state, n.Specs)
+
+ case opEmptyPackage:
+ n, ok := n.(*ast.File)
+ return ok && len(n.Imports) == 0 && len(n.Decls) == 0 && m.matchNode(state, n.Name)
+
+ default:
+ panic(fmt.Sprintf("unexpected op %s", inst.op))
+ }
+}
+
+func (m *matcher) matchNode(state *MatcherState, n ast.Node) bool {
+ return m.matchNodeWithInst(state, m.nextInst(state), n)
+}
+
+func (m *matcher) matchArgList(state *MatcherState, exprs []ast.Expr) bool {
+ inst := m.nextInst(state)
+ if inst.op != opSimpleArgList {
+ return m.matchExprSlice(state, exprs)
+ }
+ if len(exprs) != int(inst.value) {
+ return false
+ }
+ for _, x := range exprs {
+ if !m.matchNode(state, x) {
+ return false
+ }
+ }
+ return true
+}
+
+func (m *matcher) matchStmtSlice(state *MatcherState, stmts []ast.Stmt) bool {
+ matched, _ := m.matchNodeList(state, stmtSlice(stmts), false)
+ return matched != nil
+}
+
+func (m *matcher) matchExprSlice(state *MatcherState, exprs []ast.Expr) bool {
+ matched, _ := m.matchNodeList(state, ExprSlice(exprs), false)
+ return matched != nil
+}
+
+func (m *matcher) matchFieldSlice(state *MatcherState, fields []*ast.Field) bool {
+ matched, _ := m.matchNodeList(state, fieldSlice(fields), false)
+ return matched != nil
+}
+
+func (m *matcher) matchIdentSlice(state *MatcherState, idents []*ast.Ident) bool {
+ matched, _ := m.matchNodeList(state, identSlice(idents), false)
+ return matched != nil
+}
+
+func (m *matcher) matchSpecSlice(state *MatcherState, specs []ast.Spec) bool {
+ matched, _ := m.matchNodeList(state, specSlice(specs), false)
+ return matched != nil
+}
+
+// matchNodeList matches two lists of nodes. It uses a common algorithm to match
+// wildcard patterns with any number of nodes without recursion.
+func (m *matcher) matchNodeList(state *MatcherState, nodes NodeSlice, partial bool) (matched ast.Node, offset int) {
+ sliceLen := nodes.Len()
+ inst := m.nextInst(state)
+ if inst.op == opEnd {
+ if sliceLen == 0 {
+ return nodes, 0
+ }
+ return nil, -1
+ }
+ pcBase := state.pc
+ pcNext := 0
+ j := 0
+ jNext := 0
+ partialStart, partialEnd := 0, sliceLen
+
+ type restart struct {
+ matches []CapturedNode
+ pc int
+ j int
+ wildStart int
+ wildName string
+ }
+ // We need to stack these because otherwise some edge cases
+ // would not match properly. Since we have various kinds of
+ // wildcards (nodes containing them, $_, and $*_), in some cases
+ // we may have to go back and do multiple restarts to get to the
+ // right starting position.
+ var stack []restart
+ wildName := ""
+ wildStart := 0
+ push := func(next int) {
+ if next > sliceLen {
+ return // would be discarded anyway
+ }
+ pcNext = state.pc - 1
+ jNext = next
+ stack = append(stack, restart{state.capture, pcNext, next, wildStart, wildName})
+ }
+ pop := func() {
+ j = jNext
+ state.pc = pcNext
+ state.capture = stack[len(stack)-1].matches
+ wildName = stack[len(stack)-1].wildName
+ wildStart = stack[len(stack)-1].wildStart
+ stack = stack[:len(stack)-1]
+ pcNext = 0
+ jNext = 0
+ if len(stack) != 0 {
+ pcNext = stack[len(stack)-1].pc
+ jNext = stack[len(stack)-1].j
+ }
+ }
+
+ // wouldMatch returns whether the current wildcard - if any -
+ // matches the nodes we are currently trying it on.
+ wouldMatch := func() bool {
+ switch wildName {
+ case "", "_":
+ return true
+ }
+ return m.matchNamed(state, wildName, nodes.slice(wildStart, j))
+ }
+ for ; inst.op != opEnd || j < sliceLen; inst = m.nextInst(state) {
+ if inst.op != opEnd {
+ if inst.op == opNodeSeq || inst.op == opNamedNodeSeq {
+ // keep track of where this wildcard
+ // started (if name == wildName,
+ // we're trying the same wildcard
+ // matching one more node)
+ name := "_"
+ if inst.op == opNamedNodeSeq {
+ name = m.stringValue(inst)
+ }
+ if name != wildName {
+ wildStart = j
+ wildName = name
+ }
+ // try to match zero or more at j,
+ // restarting at j+1 if it fails
+ push(j + 1)
+ continue
+ }
+ if partial && state.pc == pcBase {
+ // let "b; c" match "a; b; c"
+ // (simulates a $*_ at the beginning)
+ partialStart = j
+ push(j + 1)
+ }
+ if j < sliceLen && wouldMatch() && m.matchNodeWithInst(state, inst, nodes.At(j)) {
+ // ordinary match
+ wildName = ""
+ j++
+ continue
+ }
+ }
+ if partial && inst.op == opEnd && wildName == "" {
+ partialEnd = j
+ break // let "b; c" match "b; c; d"
+ }
+ // mismatch, try to restart
+ if 0 < jNext && jNext <= sliceLen && (state.pc != pcNext || j != jNext) {
+ pop()
+ continue
+ }
+ return nil, -1
+ }
+ if !wouldMatch() {
+ return nil, -1
+ }
+ return nodes.slice(partialStart, partialEnd), partialEnd + 1
+}
+
+func (m *matcher) matchRangeClause(state *MatcherState, n ast.Node, accept func(MatchData)) {
+ rng, ok := n.(*ast.RangeStmt)
+ if !ok {
+ return
+ }
+ m.resetCapture(state)
+ if !m.matchNode(state, rng.X) {
+ return
+ }
+
+ // Now the fun begins: there is no Range pos in RangeStmt, so we need
+ // to make our best guess to find it.
+ // See https://github.com/golang/go/issues/50429
+ //
+ // In gogrep we don't have []byte sources available, and
+ // it would be cumbersome to walk bytes manually to find the "range" keyword.
+ // What we can do is to hope that code is:
+ // 1. Properly gofmt-ed.
+ // 2. There are no some freefloating artifacts between TokPos and "range".
+ var from int
+ if rng.TokPos != token.NoPos {
+ // Start from the end of the '=' or ':=' token.
+ from = int(rng.TokPos + 1)
+ if rng.Tok == token.DEFINE {
+ from++ // ':=' is 1 byte longer that '='
+ }
+ // Now suppose we have 'for _, x := range xs {...}'
+ // If this is true, then `xs.Pos.Offset - len(" range ")` would
+ // lead us to the current 'from' value.
+ // It's syntactically correct to have `:=range`, so we don't
+ // unconditionally add a space here.
+ if int(rng.X.Pos())-len(" range ") == from {
+ // This means that there is exactly one space between Tok and "range".
+ // There are some afwul cases where this might break, but let's
+ // not think about them too much.
+ from += len(" ")
+ }
+ } else {
+ // `for range xs {...}` form.
+ // There should be at least 1 space between "for" and "range".
+ from = int(rng.For) + len("for ")
+ }
+
+ state.partial.X = rng
+ state.partial.from = token.Pos(from)
+ state.partial.to = rng.X.End()
+
+ accept(MatchData{
+ Capture: state.capture,
+ Node: &state.partial,
+ })
+}
+
+func (m *matcher) matchRangeHeader(state *MatcherState, n ast.Node, accept func(MatchData)) {
+ rng, ok := n.(*ast.RangeStmt)
+ if ok && rng.Key == nil && rng.Value == nil && m.matchNode(state, rng.X) {
+ m.setRangeHeaderPos(state, rng)
+ accept(MatchData{
+ Capture: state.capture,
+ Node: &state.partial,
+ })
+ }
+}
+
+func (m *matcher) matchRangeKeyHeader(state *MatcherState, inst instruction, n ast.Node, accept func(MatchData)) {
+ rng, ok := n.(*ast.RangeStmt)
+ if ok && rng.Key != nil && rng.Value == nil && token.Token(inst.value) == rng.Tok && m.matchNode(state, rng.Key) && m.matchNode(state, rng.X) {
+ m.setRangeHeaderPos(state, rng)
+ accept(MatchData{
+ Capture: state.capture,
+ Node: &state.partial,
+ })
+ }
+}
+
+func (m *matcher) matchRangeKeyValueHeader(state *MatcherState, inst instruction, n ast.Node, accept func(MatchData)) {
+ rng, ok := n.(*ast.RangeStmt)
+ if ok && rng.Key != nil && rng.Value != nil && token.Token(inst.value) == rng.Tok && m.matchNode(state, rng.Key) && m.matchNode(state, rng.Value) && m.matchNode(state, rng.X) {
+ m.setRangeHeaderPos(state, rng)
+ accept(MatchData{
+ Capture: state.capture,
+ Node: &state.partial,
+ })
+ }
+}
+
+func (m *matcher) setRangeHeaderPos(state *MatcherState, rng *ast.RangeStmt) {
+ state.partial.X = rng
+ state.partial.from = rng.Pos()
+ state.partial.to = rng.Body.Pos() - 1
+}
+
+func findNamed(capture []CapturedNode, name string) (ast.Node, bool) {
+ for _, c := range capture {
+ if c.Name == name {
+ return c.Node, true
+ }
+ }
+ return nil, false
+}
+
+func literalValue(lit *ast.BasicLit) interface{} {
+ switch lit.Kind {
+ case token.INT:
+ v, err := strconv.ParseInt(lit.Value, 0, 64)
+ if err == nil {
+ return v
+ }
+ case token.CHAR:
+ s, err := strconv.Unquote(lit.Value)
+ if err != nil {
+ return nil
+ }
+ // Return the first rune.
+ for _, c := range s {
+ return c
+ }
+ case token.STRING:
+ s, err := strconv.Unquote(lit.Value)
+ if err == nil {
+ return s
+ }
+ case token.FLOAT:
+ v, err := strconv.ParseFloat(lit.Value, 64)
+ if err == nil {
+ return v
+ }
+ case token.IMAG:
+ v, err := strconv.ParseComplex(lit.Value, 128)
+ if err == nil {
+ return v
+ }
+ }
+ return nil
+}
+
+func equalNodes(x, y ast.Node) bool {
+ if x == nil || y == nil {
+ return x == y
+ }
+ switch x := x.(type) {
+ case stmtSlice:
+ y, ok := y.(stmtSlice)
+ if !ok || len(x) != len(y) {
+ return false
+ }
+ for i := range x {
+ if !astequal.Stmt(x[i], y[i]) {
+ return false
+ }
+ }
+ return true
+ case ExprSlice:
+ y, ok := y.(ExprSlice)
+ if !ok || len(x) != len(y) {
+ return false
+ }
+ for i := range x {
+ if !astequal.Expr(x[i], y[i]) {
+ return false
+ }
+ }
+ return true
+ case declSlice:
+ y, ok := y.(declSlice)
+ if !ok || len(x) != len(y) {
+ return false
+ }
+ for i := range x {
+ if !astequal.Decl(x[i], y[i]) {
+ return false
+ }
+ }
+ return true
+
+ default:
+ return astequal.Node(x, y)
+ }
+}
+
+func toStmtSlice(nodes ...ast.Node) stmtSlice {
+ var stmts []ast.Stmt
+ for _, node := range nodes {
+ switch x := node.(type) {
+ case nil:
+ case ast.Stmt:
+ stmts = append(stmts, x)
+ case ast.Expr:
+ stmts = append(stmts, &ast.ExprStmt{X: x})
+ default:
+ panic(fmt.Sprintf("unexpected node type: %T", x))
+ }
+ }
+ return stmtSlice(stmts)
+}
diff --git a/vendor/github.com/quasilyte/gogrep/nodetag/nodetag.go b/vendor/github.com/quasilyte/gogrep/nodetag/nodetag.go
new file mode 100644
index 000000000..a4cc2ff85
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/nodetag/nodetag.go
@@ -0,0 +1,280 @@
+package nodetag
+
+import (
+ "go/ast"
+)
+
+type Value int
+
+const (
+ Unknown Value = iota
+
+ ArrayType
+ AssignStmt
+ BasicLit
+ BinaryExpr
+ BlockStmt
+ BranchStmt
+ CallExpr
+ CaseClause
+ ChanType
+ CommClause
+ CompositeLit
+ DeclStmt
+ DeferStmt
+ Ellipsis
+ EmptyStmt
+ ExprStmt
+ File
+ ForStmt
+ FuncDecl
+ FuncLit
+ FuncType
+ GenDecl
+ GoStmt
+ Ident
+ IfStmt
+ ImportSpec
+ IncDecStmt
+ IndexExpr
+ InterfaceType
+ KeyValueExpr
+ LabeledStmt
+ MapType
+ ParenExpr
+ RangeStmt
+ ReturnStmt
+ SelectStmt
+ SelectorExpr
+ SendStmt
+ SliceExpr
+ StarExpr
+ StructType
+ SwitchStmt
+ TypeAssertExpr
+ TypeSpec
+ TypeSwitchStmt
+ UnaryExpr
+ ValueSpec
+
+ NumBuckets
+
+ StmtList // gogrep stmt list
+ ExprList // gogrep expr list
+ DeclList // gogrep decl list
+
+ Node // ast.Node
+ Expr // ast.Expr
+ Stmt // ast.Stmt
+)
+
+func FromNode(n ast.Node) Value {
+ switch n.(type) {
+ case *ast.ArrayType:
+ return ArrayType
+ case *ast.AssignStmt:
+ return AssignStmt
+ case *ast.BasicLit:
+ return BasicLit
+ case *ast.BinaryExpr:
+ return BinaryExpr
+ case *ast.BlockStmt:
+ return BlockStmt
+ case *ast.BranchStmt:
+ return BranchStmt
+ case *ast.CallExpr:
+ return CallExpr
+ case *ast.CaseClause:
+ return CaseClause
+ case *ast.ChanType:
+ return ChanType
+ case *ast.CommClause:
+ return CommClause
+ case *ast.CompositeLit:
+ return CompositeLit
+ case *ast.DeclStmt:
+ return DeclStmt
+ case *ast.DeferStmt:
+ return DeferStmt
+ case *ast.Ellipsis:
+ return Ellipsis
+ case *ast.EmptyStmt:
+ return EmptyStmt
+ case *ast.ExprStmt:
+ return ExprStmt
+ case *ast.File:
+ return File
+ case *ast.ForStmt:
+ return ForStmt
+ case *ast.FuncDecl:
+ return FuncDecl
+ case *ast.FuncLit:
+ return FuncLit
+ case *ast.FuncType:
+ return FuncType
+ case *ast.GenDecl:
+ return GenDecl
+ case *ast.GoStmt:
+ return GoStmt
+ case *ast.Ident:
+ return Ident
+ case *ast.IfStmt:
+ return IfStmt
+ case *ast.ImportSpec:
+ return ImportSpec
+ case *ast.IncDecStmt:
+ return IncDecStmt
+ case *ast.IndexExpr:
+ return IndexExpr
+ case *ast.InterfaceType:
+ return InterfaceType
+ case *ast.KeyValueExpr:
+ return KeyValueExpr
+ case *ast.LabeledStmt:
+ return LabeledStmt
+ case *ast.MapType:
+ return MapType
+ case *ast.ParenExpr:
+ return ParenExpr
+ case *ast.RangeStmt:
+ return RangeStmt
+ case *ast.ReturnStmt:
+ return ReturnStmt
+ case *ast.SelectStmt:
+ return SelectStmt
+ case *ast.SelectorExpr:
+ return SelectorExpr
+ case *ast.SendStmt:
+ return SendStmt
+ case *ast.SliceExpr:
+ return SliceExpr
+ case *ast.StarExpr:
+ return StarExpr
+ case *ast.StructType:
+ return StructType
+ case *ast.SwitchStmt:
+ return SwitchStmt
+ case *ast.TypeAssertExpr:
+ return TypeAssertExpr
+ case *ast.TypeSpec:
+ return TypeSpec
+ case *ast.TypeSwitchStmt:
+ return TypeSwitchStmt
+ case *ast.UnaryExpr:
+ return UnaryExpr
+ case *ast.ValueSpec:
+ return ValueSpec
+ default:
+ return Unknown
+ }
+}
+
+func FromString(s string) Value {
+ switch s {
+ case "Expr":
+ return Expr
+ case "Stmt":
+ return Stmt
+ case "Node":
+ return Node
+ }
+
+ switch s {
+ case "ArrayType":
+ return ArrayType
+ case "AssignStmt":
+ return AssignStmt
+ case "BasicLit":
+ return BasicLit
+ case "BinaryExpr":
+ return BinaryExpr
+ case "BlockStmt":
+ return BlockStmt
+ case "BranchStmt":
+ return BranchStmt
+ case "CallExpr":
+ return CallExpr
+ case "CaseClause":
+ return CaseClause
+ case "ChanType":
+ return ChanType
+ case "CommClause":
+ return CommClause
+ case "CompositeLit":
+ return CompositeLit
+ case "DeclStmt":
+ return DeclStmt
+ case "DeferStmt":
+ return DeferStmt
+ case "Ellipsis":
+ return Ellipsis
+ case "EmptyStmt":
+ return EmptyStmt
+ case "ExprStmt":
+ return ExprStmt
+ case "File":
+ return File
+ case "ForStmt":
+ return ForStmt
+ case "FuncDecl":
+ return FuncDecl
+ case "FuncLit":
+ return FuncLit
+ case "FuncType":
+ return FuncType
+ case "GenDecl":
+ return GenDecl
+ case "GoStmt":
+ return GoStmt
+ case "Ident":
+ return Ident
+ case "IfStmt":
+ return IfStmt
+ case "ImportSpec":
+ return ImportSpec
+ case "IncDecStmt":
+ return IncDecStmt
+ case "IndexExpr":
+ return IndexExpr
+ case "InterfaceType":
+ return InterfaceType
+ case "KeyValueExpr":
+ return KeyValueExpr
+ case "LabeledStmt":
+ return LabeledStmt
+ case "MapType":
+ return MapType
+ case "ParenExpr":
+ return ParenExpr
+ case "RangeStmt":
+ return RangeStmt
+ case "ReturnStmt":
+ return ReturnStmt
+ case "SelectStmt":
+ return SelectStmt
+ case "SelectorExpr":
+ return SelectorExpr
+ case "SendStmt":
+ return SendStmt
+ case "SliceExpr":
+ return SliceExpr
+ case "StarExpr":
+ return StarExpr
+ case "StructType":
+ return StructType
+ case "SwitchStmt":
+ return SwitchStmt
+ case "TypeAssertExpr":
+ return TypeAssertExpr
+ case "TypeSpec":
+ return TypeSpec
+ case "TypeSwitchStmt":
+ return TypeSwitchStmt
+ case "UnaryExpr":
+ return UnaryExpr
+ case "ValueSpec":
+ return ValueSpec
+ default:
+ return Unknown
+ }
+}
diff --git a/vendor/github.com/quasilyte/gogrep/operation_string.go b/vendor/github.com/quasilyte/gogrep/operation_string.go
new file mode 100644
index 000000000..fa093266e
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/operation_string.go
@@ -0,0 +1,146 @@
+// Code generated by "stringer -type=operation -trimprefix=op"; DO NOT EDIT.
+
+package gogrep
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[opInvalid-0]
+ _ = x[opNode-1]
+ _ = x[opNamedNode-2]
+ _ = x[opNodeSeq-3]
+ _ = x[opNamedNodeSeq-4]
+ _ = x[opOptNode-5]
+ _ = x[opNamedOptNode-6]
+ _ = x[opFieldNode-7]
+ _ = x[opNamedFieldNode-8]
+ _ = x[opMultiStmt-9]
+ _ = x[opMultiExpr-10]
+ _ = x[opMultiDecl-11]
+ _ = x[opEnd-12]
+ _ = x[opBasicLit-13]
+ _ = x[opStrictIntLit-14]
+ _ = x[opStrictFloatLit-15]
+ _ = x[opStrictCharLit-16]
+ _ = x[opStrictStringLit-17]
+ _ = x[opStrictComplexLit-18]
+ _ = x[opIdent-19]
+ _ = x[opPkg-20]
+ _ = x[opIndexExpr-21]
+ _ = x[opSliceExpr-22]
+ _ = x[opSliceFromExpr-23]
+ _ = x[opSliceToExpr-24]
+ _ = x[opSliceFromToExpr-25]
+ _ = x[opSliceToCapExpr-26]
+ _ = x[opSliceFromToCapExpr-27]
+ _ = x[opFuncLit-28]
+ _ = x[opCompositeLit-29]
+ _ = x[opTypedCompositeLit-30]
+ _ = x[opSimpleSelectorExpr-31]
+ _ = x[opSelectorExpr-32]
+ _ = x[opTypeAssertExpr-33]
+ _ = x[opTypeSwitchAssertExpr-34]
+ _ = x[opStructType-35]
+ _ = x[opInterfaceType-36]
+ _ = x[opVoidFuncType-37]
+ _ = x[opFuncType-38]
+ _ = x[opArrayType-39]
+ _ = x[opSliceType-40]
+ _ = x[opMapType-41]
+ _ = x[opChanType-42]
+ _ = x[opKeyValueExpr-43]
+ _ = x[opEllipsis-44]
+ _ = x[opTypedEllipsis-45]
+ _ = x[opStarExpr-46]
+ _ = x[opUnaryExpr-47]
+ _ = x[opBinaryExpr-48]
+ _ = x[opParenExpr-49]
+ _ = x[opArgList-50]
+ _ = x[opSimpleArgList-51]
+ _ = x[opVariadicCallExpr-52]
+ _ = x[opNonVariadicCallExpr-53]
+ _ = x[opCallExpr-54]
+ _ = x[opAssignStmt-55]
+ _ = x[opMultiAssignStmt-56]
+ _ = x[opBranchStmt-57]
+ _ = x[opSimpleLabeledBranchStmt-58]
+ _ = x[opLabeledBranchStmt-59]
+ _ = x[opSimpleLabeledStmt-60]
+ _ = x[opLabeledStmt-61]
+ _ = x[opBlockStmt-62]
+ _ = x[opExprStmt-63]
+ _ = x[opGoStmt-64]
+ _ = x[opDeferStmt-65]
+ _ = x[opSendStmt-66]
+ _ = x[opEmptyStmt-67]
+ _ = x[opIncDecStmt-68]
+ _ = x[opReturnStmt-69]
+ _ = x[opIfStmt-70]
+ _ = x[opIfInitStmt-71]
+ _ = x[opIfElseStmt-72]
+ _ = x[opIfInitElseStmt-73]
+ _ = x[opIfNamedOptStmt-74]
+ _ = x[opIfNamedOptElseStmt-75]
+ _ = x[opSwitchStmt-76]
+ _ = x[opSwitchTagStmt-77]
+ _ = x[opSwitchInitStmt-78]
+ _ = x[opSwitchInitTagStmt-79]
+ _ = x[opSelectStmt-80]
+ _ = x[opTypeSwitchStmt-81]
+ _ = x[opTypeSwitchInitStmt-82]
+ _ = x[opCaseClause-83]
+ _ = x[opDefaultCaseClause-84]
+ _ = x[opCommClause-85]
+ _ = x[opDefaultCommClause-86]
+ _ = x[opForStmt-87]
+ _ = x[opForPostStmt-88]
+ _ = x[opForCondStmt-89]
+ _ = x[opForCondPostStmt-90]
+ _ = x[opForInitStmt-91]
+ _ = x[opForInitPostStmt-92]
+ _ = x[opForInitCondStmt-93]
+ _ = x[opForInitCondPostStmt-94]
+ _ = x[opRangeStmt-95]
+ _ = x[opRangeKeyStmt-96]
+ _ = x[opRangeKeyValueStmt-97]
+ _ = x[opRangeClause-98]
+ _ = x[opRangeHeader-99]
+ _ = x[opRangeKeyHeader-100]
+ _ = x[opRangeKeyValueHeader-101]
+ _ = x[opFieldList-102]
+ _ = x[opUnnamedField-103]
+ _ = x[opSimpleField-104]
+ _ = x[opField-105]
+ _ = x[opMultiField-106]
+ _ = x[opValueSpec-107]
+ _ = x[opValueInitSpec-108]
+ _ = x[opTypedValueInitSpec-109]
+ _ = x[opTypedValueSpec-110]
+ _ = x[opTypeSpec-111]
+ _ = x[opTypeAliasSpec-112]
+ _ = x[opFuncDecl-113]
+ _ = x[opMethodDecl-114]
+ _ = x[opFuncProtoDecl-115]
+ _ = x[opMethodProtoDecl-116]
+ _ = x[opDeclStmt-117]
+ _ = x[opConstDecl-118]
+ _ = x[opVarDecl-119]
+ _ = x[opTypeDecl-120]
+ _ = x[opAnyImportDecl-121]
+ _ = x[opImportDecl-122]
+ _ = x[opEmptyPackage-123]
+}
+
+const _operation_name = "InvalidNodeNamedNodeNodeSeqNamedNodeSeqOptNodeNamedOptNodeFieldNodeNamedFieldNodeMultiStmtMultiExprMultiDeclEndBasicLitStrictIntLitStrictFloatLitStrictCharLitStrictStringLitStrictComplexLitIdentPkgIndexExprSliceExprSliceFromExprSliceToExprSliceFromToExprSliceToCapExprSliceFromToCapExprFuncLitCompositeLitTypedCompositeLitSimpleSelectorExprSelectorExprTypeAssertExprTypeSwitchAssertExprStructTypeInterfaceTypeVoidFuncTypeFuncTypeArrayTypeSliceTypeMapTypeChanTypeKeyValueExprEllipsisTypedEllipsisStarExprUnaryExprBinaryExprParenExprArgListSimpleArgListVariadicCallExprNonVariadicCallExprCallExprAssignStmtMultiAssignStmtBranchStmtSimpleLabeledBranchStmtLabeledBranchStmtSimpleLabeledStmtLabeledStmtBlockStmtExprStmtGoStmtDeferStmtSendStmtEmptyStmtIncDecStmtReturnStmtIfStmtIfInitStmtIfElseStmtIfInitElseStmtIfNamedOptStmtIfNamedOptElseStmtSwitchStmtSwitchTagStmtSwitchInitStmtSwitchInitTagStmtSelectStmtTypeSwitchStmtTypeSwitchInitStmtCaseClauseDefaultCaseClauseCommClauseDefaultCommClauseForStmtForPostStmtForCondStmtForCondPostStmtForInitStmtForInitPostStmtForInitCondStmtForInitCondPostStmtRangeStmtRangeKeyStmtRangeKeyValueStmtRangeClauseRangeHeaderRangeKeyHeaderRangeKeyValueHeaderFieldListUnnamedFieldSimpleFieldFieldMultiFieldValueSpecValueInitSpecTypedValueInitSpecTypedValueSpecTypeSpecTypeAliasSpecFuncDeclMethodDeclFuncProtoDeclMethodProtoDeclDeclStmtConstDeclVarDeclTypeDeclAnyImportDeclImportDeclEmptyPackage"
+
+var _operation_index = [...]uint16{0, 7, 11, 20, 27, 39, 46, 58, 67, 81, 90, 99, 108, 111, 119, 131, 145, 158, 173, 189, 194, 197, 206, 215, 228, 239, 254, 268, 286, 293, 305, 322, 340, 352, 366, 386, 396, 409, 421, 429, 438, 447, 454, 462, 474, 482, 495, 503, 512, 522, 531, 538, 551, 567, 586, 594, 604, 619, 629, 652, 669, 686, 697, 706, 714, 720, 729, 737, 746, 756, 766, 772, 782, 792, 806, 820, 838, 848, 861, 875, 892, 902, 916, 934, 944, 961, 971, 988, 995, 1006, 1017, 1032, 1043, 1058, 1073, 1092, 1101, 1113, 1130, 1141, 1152, 1166, 1185, 1194, 1206, 1217, 1222, 1232, 1241, 1254, 1272, 1286, 1294, 1307, 1315, 1325, 1338, 1353, 1361, 1370, 1377, 1385, 1398, 1408, 1420}
+
+func (i operation) String() string {
+ if i >= operation(len(_operation_index)-1) {
+ return "operation(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _operation_name[_operation_index[i]:_operation_index[i+1]]
+}
diff --git a/vendor/github.com/quasilyte/gogrep/operations.gen.go b/vendor/github.com/quasilyte/gogrep/operations.gen.go
new file mode 100644
index 000000000..8ff1fbeb7
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/operations.gen.go
@@ -0,0 +1,1570 @@
+// Code generated "gen_operations.go"; DO NOT EDIT.
+
+package gogrep
+
+import (
+ "github.com/quasilyte/gogrep/nodetag"
+)
+
+//go:generate stringer -type=operation -trimprefix=op
+type operation uint8
+
+const (
+ opInvalid operation = 0
+
+ // Tag: Node
+ opNode operation = 1
+
+ // Tag: Node
+ // ValueIndex: strings | wildcard name
+ opNamedNode operation = 2
+
+ // Tag: Unknown
+ opNodeSeq operation = 3
+
+ // Tag: Unknown
+ // ValueIndex: strings | wildcard name
+ opNamedNodeSeq operation = 4
+
+ // Tag: Unknown
+ opOptNode operation = 5
+
+ // Tag: Unknown
+ // ValueIndex: strings | wildcard name
+ opNamedOptNode operation = 6
+
+ // Tag: Node
+ opFieldNode operation = 7
+
+ // Tag: Node
+ // ValueIndex: strings | wildcard name
+ opNamedFieldNode operation = 8
+
+ // Tag: StmtList
+ // Args: stmts...
+ // Example: f(); g()
+ opMultiStmt operation = 9
+
+ // Tag: ExprList
+ // Args: exprs...
+ // Example: f(), g()
+ opMultiExpr operation = 10
+
+ // Tag: DeclList
+ // Args: exprs...
+ // Example: f(), g()
+ opMultiDecl operation = 11
+
+ // Tag: Unknown
+ opEnd operation = 12
+
+ // Tag: BasicLit
+ // ValueIndex: ifaces | parsed literal value
+ opBasicLit operation = 13
+
+ // Tag: BasicLit
+ // ValueIndex: strings | raw literal value
+ opStrictIntLit operation = 14
+
+ // Tag: BasicLit
+ // ValueIndex: strings | raw literal value
+ opStrictFloatLit operation = 15
+
+ // Tag: BasicLit
+ // ValueIndex: strings | raw literal value
+ opStrictCharLit operation = 16
+
+ // Tag: BasicLit
+ // ValueIndex: strings | raw literal value
+ opStrictStringLit operation = 17
+
+ // Tag: BasicLit
+ // ValueIndex: strings | raw literal value
+ opStrictComplexLit operation = 18
+
+ // Tag: Ident
+ // ValueIndex: strings | ident name
+ opIdent operation = 19
+
+ // Tag: Ident
+ // ValueIndex: strings | package path
+ opPkg operation = 20
+
+ // Tag: IndexExpr
+ // Args: x expr
+ opIndexExpr operation = 21
+
+ // Tag: SliceExpr
+ // Args: x
+ opSliceExpr operation = 22
+
+ // Tag: SliceExpr
+ // Args: x from
+ // Example: x[from:]
+ opSliceFromExpr operation = 23
+
+ // Tag: SliceExpr
+ // Args: x to
+ // Example: x[:to]
+ opSliceToExpr operation = 24
+
+ // Tag: SliceExpr
+ // Args: x from to
+ // Example: x[from:to]
+ opSliceFromToExpr operation = 25
+
+ // Tag: SliceExpr
+ // Args: x from cap
+ // Example: x[:from:cap]
+ opSliceToCapExpr operation = 26
+
+ // Tag: SliceExpr
+ // Args: x from to cap
+ // Example: x[from:to:cap]
+ opSliceFromToCapExpr operation = 27
+
+ // Tag: FuncLit
+ // Args: type block
+ opFuncLit operation = 28
+
+ // Tag: CompositeLit
+ // Args: elts...
+ // Example: {elts...}
+ opCompositeLit operation = 29
+
+ // Tag: CompositeLit
+ // Args: typ elts...
+ // Example: typ{elts...}
+ opTypedCompositeLit operation = 30
+
+ // Tag: SelectorExpr
+ // Args: x
+ // ValueIndex: strings | selector name
+ opSimpleSelectorExpr operation = 31
+
+ // Tag: SelectorExpr
+ // Args: x sel
+ opSelectorExpr operation = 32
+
+ // Tag: TypeAssertExpr
+ // Args: x typ
+ opTypeAssertExpr operation = 33
+
+ // Tag: TypeAssertExpr
+ // Args: x
+ opTypeSwitchAssertExpr operation = 34
+
+ // Tag: StructType
+ // Args: fields
+ opStructType operation = 35
+
+ // Tag: StructType
+ // Args: fields
+ opInterfaceType operation = 36
+
+ // Tag: FuncType
+ // Args: params
+ opVoidFuncType operation = 37
+
+ // Tag: FuncType
+ // Args: params results
+ opFuncType operation = 38
+
+ // Tag: ArrayType
+ // Args: length elem
+ opArrayType operation = 39
+
+ // Tag: ArrayType
+ // Args: elem
+ opSliceType operation = 40
+
+ // Tag: MapType
+ // Args: key value
+ opMapType operation = 41
+
+ // Tag: ChanType
+ // Args: value
+ // Value: ast.ChanDir | channel direction
+ opChanType operation = 42
+
+ // Tag: KeyValueExpr
+ // Args: key value
+ opKeyValueExpr operation = 43
+
+ // Tag: Ellipsis
+ opEllipsis operation = 44
+
+ // Tag: Ellipsis
+ // Args: type
+ opTypedEllipsis operation = 45
+
+ // Tag: StarExpr
+ // Args: x
+ opStarExpr operation = 46
+
+ // Tag: UnaryExpr
+ // Args: x
+ // Value: token.Token | unary operator
+ opUnaryExpr operation = 47
+
+ // Tag: BinaryExpr
+ // Args: x y
+ // Value: token.Token | binary operator
+ opBinaryExpr operation = 48
+
+ // Tag: ParenExpr
+ // Args: x
+ opParenExpr operation = 49
+
+ // Tag: Unknown
+ // Args: exprs...
+ // Example: 1, 2, 3
+ opArgList operation = 50
+
+ // Tag: Unknown
+ // Like ArgList, but pattern contains no $*
+ // Args: exprs[]
+ // Example: 1, 2, 3
+ // Value: int | slice len
+ opSimpleArgList operation = 51
+
+ // Tag: CallExpr
+ // Args: fn args
+ // Example: f(1, xs...)
+ opVariadicCallExpr operation = 52
+
+ // Tag: CallExpr
+ // Args: fn args
+ // Example: f(1, xs)
+ opNonVariadicCallExpr operation = 53
+
+ // Tag: CallExpr
+ // Args: fn args
+ // Example: f(1, xs) or f(1, xs...)
+ opCallExpr operation = 54
+
+ // Tag: AssignStmt
+ // Args: lhs rhs
+ // Example: lhs := rhs()
+ // Value: token.Token | ':=' or '='
+ opAssignStmt operation = 55
+
+ // Tag: AssignStmt
+ // Args: lhs... rhs...
+ // Example: lhs1, lhs2 := rhs()
+ // Value: token.Token | ':=' or '='
+ opMultiAssignStmt operation = 56
+
+ // Tag: BranchStmt
+ // Args: x
+ // Value: token.Token | branch kind
+ opBranchStmt operation = 57
+
+ // Tag: BranchStmt
+ // Args: x
+ // Value: token.Token | branch kind
+ // ValueIndex: strings | label name
+ opSimpleLabeledBranchStmt operation = 58
+
+ // Tag: BranchStmt
+ // Args: label x
+ // Value: token.Token | branch kind
+ opLabeledBranchStmt operation = 59
+
+ // Tag: LabeledStmt
+ // Args: x
+ // ValueIndex: strings | label name
+ opSimpleLabeledStmt operation = 60
+
+ // Tag: LabeledStmt
+ // Args: label x
+ opLabeledStmt operation = 61
+
+ // Tag: BlockStmt
+ // Args: body...
+ opBlockStmt operation = 62
+
+ // Tag: ExprStmt
+ // Args: x
+ opExprStmt operation = 63
+
+ // Tag: GoStmt
+ // Args: x
+ opGoStmt operation = 64
+
+ // Tag: DeferStmt
+ // Args: x
+ opDeferStmt operation = 65
+
+ // Tag: SendStmt
+ // Args: ch value
+ opSendStmt operation = 66
+
+ // Tag: EmptyStmt
+ opEmptyStmt operation = 67
+
+ // Tag: IncDecStmt
+ // Args: x
+ // Value: token.Token | '++' or '--'
+ opIncDecStmt operation = 68
+
+ // Tag: ReturnStmt
+ // Args: results...
+ opReturnStmt operation = 69
+
+ // Tag: IfStmt
+ // Args: cond block
+ // Example: if cond {}
+ opIfStmt operation = 70
+
+ // Tag: IfStmt
+ // Args: init cond block
+ // Example: if init; cond {}
+ opIfInitStmt operation = 71
+
+ // Tag: IfStmt
+ // Args: cond block else
+ // Example: if cond {} else ...
+ opIfElseStmt operation = 72
+
+ // Tag: IfStmt
+ // Args: init cond block else
+ // Example: if init; cond {} else ...
+ opIfInitElseStmt operation = 73
+
+ // Tag: IfStmt
+ // Args: block
+ // Example: if $*x {}
+ // ValueIndex: strings | wildcard name
+ opIfNamedOptStmt operation = 74
+
+ // Tag: IfStmt
+ // Args: block else
+ // Example: if $*x {} else ...
+ // ValueIndex: strings | wildcard name
+ opIfNamedOptElseStmt operation = 75
+
+ // Tag: SwitchStmt
+ // Args: body...
+ // Example: switch {}
+ opSwitchStmt operation = 76
+
+ // Tag: SwitchStmt
+ // Args: tag body...
+ // Example: switch tag {}
+ opSwitchTagStmt operation = 77
+
+ // Tag: SwitchStmt
+ // Args: init body...
+ // Example: switch init; {}
+ opSwitchInitStmt operation = 78
+
+ // Tag: SwitchStmt
+ // Args: init tag body...
+ // Example: switch init; tag {}
+ opSwitchInitTagStmt operation = 79
+
+ // Tag: SelectStmt
+ // Args: body...
+ opSelectStmt operation = 80
+
+ // Tag: TypeSwitchStmt
+ // Args: x block
+ // Example: switch x.(type) {}
+ opTypeSwitchStmt operation = 81
+
+ // Tag: TypeSwitchStmt
+ // Args: init x block
+ // Example: switch init; x.(type) {}
+ opTypeSwitchInitStmt operation = 82
+
+ // Tag: CaseClause
+ // Args: values... body...
+ opCaseClause operation = 83
+
+ // Tag: CaseClause
+ // Args: body...
+ opDefaultCaseClause operation = 84
+
+ // Tag: CommClause
+ // Args: comm body...
+ opCommClause operation = 85
+
+ // Tag: CommClause
+ // Args: body...
+ opDefaultCommClause operation = 86
+
+ // Tag: ForStmt
+ // Args: blocl
+ // Example: for {}
+ opForStmt operation = 87
+
+ // Tag: ForStmt
+ // Args: post block
+ // Example: for ; ; post {}
+ opForPostStmt operation = 88
+
+ // Tag: ForStmt
+ // Args: cond block
+ // Example: for ; cond; {}
+ opForCondStmt operation = 89
+
+ // Tag: ForStmt
+ // Args: cond post block
+ // Example: for ; cond; post {}
+ opForCondPostStmt operation = 90
+
+ // Tag: ForStmt
+ // Args: init block
+ // Example: for init; ; {}
+ opForInitStmt operation = 91
+
+ // Tag: ForStmt
+ // Args: init post block
+ // Example: for init; ; post {}
+ opForInitPostStmt operation = 92
+
+ // Tag: ForStmt
+ // Args: init cond block
+ // Example: for init; cond; {}
+ opForInitCondStmt operation = 93
+
+ // Tag: ForStmt
+ // Args: init cond post block
+ // Example: for init; cond; post {}
+ opForInitCondPostStmt operation = 94
+
+ // Tag: RangeStmt
+ // Args: x block
+ // Example: for range x {}
+ opRangeStmt operation = 95
+
+ // Tag: RangeStmt
+ // Args: key x block
+ // Example: for key := range x {}
+ // Value: token.Token | ':=' or '='
+ opRangeKeyStmt operation = 96
+
+ // Tag: RangeStmt
+ // Args: key value x block
+ // Example: for key, value := range x {}
+ // Value: token.Token | ':=' or '='
+ opRangeKeyValueStmt operation = 97
+
+ // Tag: RangeStmt
+ // Args: x
+ // Example: range x
+ opRangeClause operation = 98
+
+ // Tag: RangeStmt
+ // Args: x
+ // Example: for range x
+ opRangeHeader operation = 99
+
+ // Tag: RangeStmt
+ // Args: key x
+ // Example: for key := range x
+ // Value: token.Token | ':=' or '='
+ opRangeKeyHeader operation = 100
+
+ // Tag: RangeStmt
+ // Args: key value x
+ // Example: for key, value := range x
+ // Value: token.Token | ':=' or '='
+ opRangeKeyValueHeader operation = 101
+
+ // Tag: Unknown
+ // Args: fields...
+ opFieldList operation = 102
+
+ // Tag: Unknown
+ // Args: typ
+ // Example: type
+ opUnnamedField operation = 103
+
+ // Tag: Unknown
+ // Args: typ
+ // Example: name type
+ // ValueIndex: strings | field name
+ opSimpleField operation = 104
+
+ // Tag: Unknown
+ // Args: name typ
+ // Example: $name type
+ opField operation = 105
+
+ // Tag: Unknown
+ // Args: names... typ
+ // Example: name1, name2 type
+ opMultiField operation = 106
+
+ // Tag: ValueSpec
+ // Args: value
+ opValueSpec operation = 107
+
+ // Tag: ValueSpec
+ // Args: lhs... rhs...
+ // Example: lhs = rhs
+ opValueInitSpec operation = 108
+
+ // Tag: ValueSpec
+ // Args: lhs... type rhs...
+ // Example: lhs typ = rhs
+ opTypedValueInitSpec operation = 109
+
+ // Tag: ValueSpec
+ // Args: lhs... type
+ // Example: lhs typ
+ opTypedValueSpec operation = 110
+
+ // Tag: TypeSpec
+ // Args: name type
+ // Example: name type
+ opTypeSpec operation = 111
+
+ // Tag: TypeSpec
+ // Args: name type
+ // Example: name = type
+ opTypeAliasSpec operation = 112
+
+ // Tag: FuncDecl
+ // Args: name type block
+ opFuncDecl operation = 113
+
+ // Tag: FuncDecl
+ // Args: recv name type block
+ opMethodDecl operation = 114
+
+ // Tag: FuncDecl
+ // Args: name type
+ opFuncProtoDecl operation = 115
+
+ // Tag: FuncDecl
+ // Args: recv name type
+ opMethodProtoDecl operation = 116
+
+ // Tag: DeclStmt
+ // Args: decl
+ opDeclStmt operation = 117
+
+ // Tag: GenDecl
+ // Args: valuespecs...
+ opConstDecl operation = 118
+
+ // Tag: GenDecl
+ // Args: valuespecs...
+ opVarDecl operation = 119
+
+ // Tag: GenDecl
+ // Args: typespecs...
+ opTypeDecl operation = 120
+
+ // Tag: GenDecl
+ opAnyImportDecl operation = 121
+
+ // Tag: GenDecl
+ // Args: importspecs...
+ opImportDecl operation = 122
+
+ // Tag: File
+ // Args: name
+ opEmptyPackage operation = 123
+)
+
+type operationInfo struct {
+ Tag nodetag.Value
+ NumArgs int
+ ValueKind valueKind
+ ExtraValueKind valueKind
+ VariadicMap bitmap64
+ SliceIndex int
+}
+
+var operationInfoTable = [256]operationInfo{
+ opInvalid: {},
+
+ opNode: {
+ Tag: nodetag.Node,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opNamedNode: {
+ Tag: nodetag.Node,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opNodeSeq: {
+ Tag: nodetag.Unknown,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opNamedNodeSeq: {
+ Tag: nodetag.Unknown,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opOptNode: {
+ Tag: nodetag.Unknown,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opNamedOptNode: {
+ Tag: nodetag.Unknown,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opFieldNode: {
+ Tag: nodetag.Node,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opNamedFieldNode: {
+ Tag: nodetag.Node,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opMultiStmt: {
+ Tag: nodetag.StmtList,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opMultiExpr: {
+ Tag: nodetag.ExprList,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opMultiDecl: {
+ Tag: nodetag.DeclList,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opEnd: {
+ Tag: nodetag.Unknown,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opBasicLit: {
+ Tag: nodetag.BasicLit,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: ifaceValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opStrictIntLit: {
+ Tag: nodetag.BasicLit,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opStrictFloatLit: {
+ Tag: nodetag.BasicLit,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opStrictCharLit: {
+ Tag: nodetag.BasicLit,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opStrictStringLit: {
+ Tag: nodetag.BasicLit,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opStrictComplexLit: {
+ Tag: nodetag.BasicLit,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opIdent: {
+ Tag: nodetag.Ident,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opPkg: {
+ Tag: nodetag.Ident,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opIndexExpr: {
+ Tag: nodetag.IndexExpr,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSliceExpr: {
+ Tag: nodetag.SliceExpr,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSliceFromExpr: {
+ Tag: nodetag.SliceExpr,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSliceToExpr: {
+ Tag: nodetag.SliceExpr,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSliceFromToExpr: {
+ Tag: nodetag.SliceExpr,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSliceToCapExpr: {
+ Tag: nodetag.SliceExpr,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSliceFromToCapExpr: {
+ Tag: nodetag.SliceExpr,
+ NumArgs: 4,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opFuncLit: {
+ Tag: nodetag.FuncLit,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opCompositeLit: {
+ Tag: nodetag.CompositeLit,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opTypedCompositeLit: {
+ Tag: nodetag.CompositeLit,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 2, // 10
+ SliceIndex: -1,
+ },
+ opSimpleSelectorExpr: {
+ Tag: nodetag.SelectorExpr,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSelectorExpr: {
+ Tag: nodetag.SelectorExpr,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opTypeAssertExpr: {
+ Tag: nodetag.TypeAssertExpr,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opTypeSwitchAssertExpr: {
+ Tag: nodetag.TypeAssertExpr,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opStructType: {
+ Tag: nodetag.StructType,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opInterfaceType: {
+ Tag: nodetag.StructType,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opVoidFuncType: {
+ Tag: nodetag.FuncType,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opFuncType: {
+ Tag: nodetag.FuncType,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opArrayType: {
+ Tag: nodetag.ArrayType,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSliceType: {
+ Tag: nodetag.ArrayType,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opMapType: {
+ Tag: nodetag.MapType,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opChanType: {
+ Tag: nodetag.ChanType,
+ NumArgs: 1,
+ ValueKind: chandirValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opKeyValueExpr: {
+ Tag: nodetag.KeyValueExpr,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opEllipsis: {
+ Tag: nodetag.Ellipsis,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opTypedEllipsis: {
+ Tag: nodetag.Ellipsis,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opStarExpr: {
+ Tag: nodetag.StarExpr,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opUnaryExpr: {
+ Tag: nodetag.UnaryExpr,
+ NumArgs: 1,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opBinaryExpr: {
+ Tag: nodetag.BinaryExpr,
+ NumArgs: 2,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opParenExpr: {
+ Tag: nodetag.ParenExpr,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opArgList: {
+ Tag: nodetag.Unknown,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opSimpleArgList: {
+ Tag: nodetag.Unknown,
+ NumArgs: 1,
+ ValueKind: intValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: 0,
+ },
+ opVariadicCallExpr: {
+ Tag: nodetag.CallExpr,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opNonVariadicCallExpr: {
+ Tag: nodetag.CallExpr,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opCallExpr: {
+ Tag: nodetag.CallExpr,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opAssignStmt: {
+ Tag: nodetag.AssignStmt,
+ NumArgs: 2,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opMultiAssignStmt: {
+ Tag: nodetag.AssignStmt,
+ NumArgs: 2,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 3, // 11
+ SliceIndex: -1,
+ },
+ opBranchStmt: {
+ Tag: nodetag.BranchStmt,
+ NumArgs: 1,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSimpleLabeledBranchStmt: {
+ Tag: nodetag.BranchStmt,
+ NumArgs: 1,
+ ValueKind: tokenValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opLabeledBranchStmt: {
+ Tag: nodetag.BranchStmt,
+ NumArgs: 2,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSimpleLabeledStmt: {
+ Tag: nodetag.LabeledStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opLabeledStmt: {
+ Tag: nodetag.LabeledStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opBlockStmt: {
+ Tag: nodetag.BlockStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opExprStmt: {
+ Tag: nodetag.ExprStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opGoStmt: {
+ Tag: nodetag.GoStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opDeferStmt: {
+ Tag: nodetag.DeferStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSendStmt: {
+ Tag: nodetag.SendStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opEmptyStmt: {
+ Tag: nodetag.EmptyStmt,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opIncDecStmt: {
+ Tag: nodetag.IncDecStmt,
+ NumArgs: 1,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opReturnStmt: {
+ Tag: nodetag.ReturnStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opIfStmt: {
+ Tag: nodetag.IfStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opIfInitStmt: {
+ Tag: nodetag.IfStmt,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opIfElseStmt: {
+ Tag: nodetag.IfStmt,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opIfInitElseStmt: {
+ Tag: nodetag.IfStmt,
+ NumArgs: 4,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opIfNamedOptStmt: {
+ Tag: nodetag.IfStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opIfNamedOptElseStmt: {
+ Tag: nodetag.IfStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSwitchStmt: {
+ Tag: nodetag.SwitchStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opSwitchTagStmt: {
+ Tag: nodetag.SwitchStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 2, // 10
+ SliceIndex: -1,
+ },
+ opSwitchInitStmt: {
+ Tag: nodetag.SwitchStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 2, // 10
+ SliceIndex: -1,
+ },
+ opSwitchInitTagStmt: {
+ Tag: nodetag.SwitchStmt,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 4, // 100
+ SliceIndex: -1,
+ },
+ opSelectStmt: {
+ Tag: nodetag.SelectStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opTypeSwitchStmt: {
+ Tag: nodetag.TypeSwitchStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opTypeSwitchInitStmt: {
+ Tag: nodetag.TypeSwitchStmt,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opCaseClause: {
+ Tag: nodetag.CaseClause,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 3, // 11
+ SliceIndex: -1,
+ },
+ opDefaultCaseClause: {
+ Tag: nodetag.CaseClause,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opCommClause: {
+ Tag: nodetag.CommClause,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 2, // 10
+ SliceIndex: -1,
+ },
+ opDefaultCommClause: {
+ Tag: nodetag.CommClause,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opForStmt: {
+ Tag: nodetag.ForStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opForPostStmt: {
+ Tag: nodetag.ForStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opForCondStmt: {
+ Tag: nodetag.ForStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opForCondPostStmt: {
+ Tag: nodetag.ForStmt,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opForInitStmt: {
+ Tag: nodetag.ForStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opForInitPostStmt: {
+ Tag: nodetag.ForStmt,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opForInitCondStmt: {
+ Tag: nodetag.ForStmt,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opForInitCondPostStmt: {
+ Tag: nodetag.ForStmt,
+ NumArgs: 4,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opRangeStmt: {
+ Tag: nodetag.RangeStmt,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opRangeKeyStmt: {
+ Tag: nodetag.RangeStmt,
+ NumArgs: 3,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opRangeKeyValueStmt: {
+ Tag: nodetag.RangeStmt,
+ NumArgs: 4,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opRangeClause: {
+ Tag: nodetag.RangeStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opRangeHeader: {
+ Tag: nodetag.RangeStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opRangeKeyHeader: {
+ Tag: nodetag.RangeStmt,
+ NumArgs: 2,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opRangeKeyValueHeader: {
+ Tag: nodetag.RangeStmt,
+ NumArgs: 3,
+ ValueKind: tokenValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opFieldList: {
+ Tag: nodetag.Unknown,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opUnnamedField: {
+ Tag: nodetag.Unknown,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opSimpleField: {
+ Tag: nodetag.Unknown,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: stringValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opField: {
+ Tag: nodetag.Unknown,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opMultiField: {
+ Tag: nodetag.Unknown,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opValueSpec: {
+ Tag: nodetag.ValueSpec,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opValueInitSpec: {
+ Tag: nodetag.ValueSpec,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 3, // 11
+ SliceIndex: -1,
+ },
+ opTypedValueInitSpec: {
+ Tag: nodetag.ValueSpec,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 5, // 101
+ SliceIndex: -1,
+ },
+ opTypedValueSpec: {
+ Tag: nodetag.ValueSpec,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opTypeSpec: {
+ Tag: nodetag.TypeSpec,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opTypeAliasSpec: {
+ Tag: nodetag.TypeSpec,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opFuncDecl: {
+ Tag: nodetag.FuncDecl,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opMethodDecl: {
+ Tag: nodetag.FuncDecl,
+ NumArgs: 4,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opFuncProtoDecl: {
+ Tag: nodetag.FuncDecl,
+ NumArgs: 2,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opMethodProtoDecl: {
+ Tag: nodetag.FuncDecl,
+ NumArgs: 3,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opDeclStmt: {
+ Tag: nodetag.DeclStmt,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opConstDecl: {
+ Tag: nodetag.GenDecl,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opVarDecl: {
+ Tag: nodetag.GenDecl,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opTypeDecl: {
+ Tag: nodetag.GenDecl,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opAnyImportDecl: {
+ Tag: nodetag.GenDecl,
+ NumArgs: 0,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+ opImportDecl: {
+ Tag: nodetag.GenDecl,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 1, // 1
+ SliceIndex: -1,
+ },
+ opEmptyPackage: {
+ Tag: nodetag.File,
+ NumArgs: 1,
+ ValueKind: emptyValue,
+ ExtraValueKind: emptyValue,
+ VariadicMap: 0, // 0
+ SliceIndex: -1,
+ },
+}
diff --git a/vendor/github.com/quasilyte/gogrep/parse.go b/vendor/github.com/quasilyte/gogrep/parse.go
new file mode 100644
index 000000000..f70c4a8f4
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/parse.go
@@ -0,0 +1,397 @@
+// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
+// See LICENSE for licensing information
+
+package gogrep
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "strings"
+ "text/template"
+)
+
+func transformSource(expr string) (string, []posOffset, error) {
+ toks, err := tokenize([]byte(expr))
+ if err != nil {
+ return "", nil, fmt.Errorf("cannot tokenize expr: %v", err)
+ }
+ var offs []posOffset
+ lbuf := lineColBuffer{line: 1, col: 1}
+ lastLit := false
+ for _, t := range toks {
+ if lbuf.offs >= t.pos.Offset && lastLit && t.lit != "" {
+ _, _ = lbuf.WriteString(" ")
+ }
+ for lbuf.offs < t.pos.Offset {
+ _, _ = lbuf.WriteString(" ")
+ }
+ if t.lit == "" {
+ _, _ = lbuf.WriteString(t.tok.String())
+ lastLit = false
+ continue
+ }
+ _, _ = lbuf.WriteString(t.lit)
+ lastLit = strings.TrimSpace(t.lit) != ""
+ }
+ // trailing newlines can cause issues with commas
+ return strings.TrimSpace(lbuf.String()), offs, nil
+}
+
+func parseExpr(fset *token.FileSet, expr string) (ast.Node, error) {
+ exprStr, offs, err := transformSource(expr)
+ if err != nil {
+ return nil, err
+ }
+ node, err := parseDetectingNode(fset, exprStr)
+ if err != nil {
+ err = subPosOffsets(err, offs...)
+ return nil, fmt.Errorf("cannot parse expr: %v", err)
+ }
+ return node, nil
+}
+
+type lineColBuffer struct {
+ bytes.Buffer
+ line, col, offs int
+}
+
+func (l *lineColBuffer) WriteString(s string) (n int, err error) {
+ for _, r := range s {
+ if r == '\n' {
+ l.line++
+ l.col = 1
+ } else {
+ l.col++
+ }
+ l.offs++
+ }
+ return l.Buffer.WriteString(s)
+}
+
+var tmplDecl = template.Must(template.New("").Parse(`` +
+ `package p; {{ . }}`))
+
+var tmplBlock = template.Must(template.New("").Parse(`` +
+ `package p; func _() { if true {{ . }} else {} }`))
+
+var tmplExprs = template.Must(template.New("").Parse(`` +
+ `package p; var _ = []interface{}{ {{ . }}, }`))
+
+var tmplStmts = template.Must(template.New("").Parse(`` +
+ `package p; func _() { {{ . }} }`))
+
+var tmplType = template.Must(template.New("").Parse(`` +
+ `package p; var _ {{ . }}`))
+
+var tmplValSpec = template.Must(template.New("").Parse(`` +
+ `package p; var {{ . }}`))
+
+func execTmpl(tmpl *template.Template, src string) string {
+ var buf bytes.Buffer
+ if err := tmpl.Execute(&buf, src); err != nil {
+ panic(err)
+ }
+ return buf.String()
+}
+
+func noBadNodes(node ast.Node) bool {
+ any := false
+ ast.Inspect(node, func(n ast.Node) bool {
+ if any {
+ return false
+ }
+ switch n.(type) {
+ case *ast.BadExpr, *ast.BadDecl:
+ any = true
+ }
+ return true
+ })
+ return !any
+}
+
+func parseType(fset *token.FileSet, src string) (ast.Expr, *ast.File, error) {
+ asType := execTmpl(tmplType, src)
+ f, err := parser.ParseFile(fset, "", asType, 0)
+ if err != nil {
+ err = subPosOffsets(err, posOffset{1, 1, 17})
+ return nil, nil, err
+ }
+ vs := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
+ return vs.Type, f, nil
+}
+
+// parseDetectingNode tries its best to parse the ast.Node contained in src, as
+// one of: *ast.File, ast.Decl, ast.Expr, ast.Stmt, *ast.ValueSpec.
+// It also returns the *ast.File used for the parsing, so that the returned node
+// can be easily type-checked.
+func parseDetectingNode(fset *token.FileSet, src string) (ast.Node, error) {
+ file := fset.AddFile("", fset.Base(), len(src))
+ scan := scanner.Scanner{}
+ scan.Init(file, []byte(src), nil, 0)
+ if _, tok, _ := scan.Scan(); tok == token.EOF {
+ return nil, fmt.Errorf("empty source code")
+ }
+ var mainErr error
+
+ // Some adhoc patterns first.
+ if strings.HasPrefix(src, "range ") {
+ e, err := parser.ParseExpr(src[len("range "):])
+ if err == nil && noBadNodes(e) {
+ return &rangeClause{X: e}, nil
+ }
+ }
+ if strings.HasPrefix(src, "for ") && !strings.HasSuffix(src, "}") {
+ asStmts := execTmpl(tmplStmts, src+"{}")
+ f, err := parser.ParseFile(fset, "", asStmts, 0)
+ if err == nil && noBadNodes(f) {
+ bl := f.Decls[0].(*ast.FuncDecl).Body
+ if len(bl.List) == 1 {
+ return &rangeHeader{Node: bl.List[0].(*ast.RangeStmt)}, nil
+ }
+ }
+ }
+
+ // try as a block; otherwise blocks might be mistaken for composite
+ // literals further below
+ asBlock := execTmpl(tmplBlock, src)
+ if f, err := parser.ParseFile(fset, "", asBlock, 0); err == nil && noBadNodes(f) {
+ bl := f.Decls[0].(*ast.FuncDecl).Body
+ if len(bl.List) == 1 {
+ ifs := bl.List[0].(*ast.IfStmt)
+ return ifs.Body, nil
+ }
+ }
+
+ // then as value expressions
+ asExprs := execTmpl(tmplExprs, src)
+ if f, err := parser.ParseFile(fset, "", asExprs, 0); err == nil && noBadNodes(f) {
+ vs := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
+ cl := vs.Values[0].(*ast.CompositeLit)
+ if len(cl.Elts) == 1 {
+ return cl.Elts[0], nil
+ }
+ return ExprSlice(cl.Elts), nil
+ }
+
+ // then try as statements
+ asStmts := execTmpl(tmplStmts, src)
+ f, err := parser.ParseFile(fset, "", asStmts, 0)
+ if err == nil && noBadNodes(f) {
+ bl := f.Decls[0].(*ast.FuncDecl).Body
+ if len(bl.List) == 1 {
+ return bl.List[0], nil
+ }
+ return stmtSlice(bl.List), nil
+ }
+ // Statements is what covers most cases, so it will give
+ // the best overall error message. Show positions
+ // relative to where the user's code is put in the
+ // template.
+ mainErr = subPosOffsets(err, posOffset{1, 1, 22})
+
+ // try as a single declaration, or many
+ asDecl := execTmpl(tmplDecl, src)
+ if f, err := parser.ParseFile(fset, "", asDecl, 0); err == nil && noBadNodes(f) {
+ if len(f.Decls) == 1 {
+ return f.Decls[0], nil
+ }
+ return declSlice(f.Decls), nil
+ }
+
+ // try as a whole file
+ if f, err := parser.ParseFile(fset, "", src, 0); err == nil && noBadNodes(f) {
+ return f, nil
+ }
+
+ // type expressions not yet picked up, for e.g. chans and interfaces
+ if typ, f, err := parseType(fset, src); err == nil && noBadNodes(f) {
+ return typ, nil
+ }
+
+ // value specs
+ asValSpec := execTmpl(tmplValSpec, src)
+ if f, err := parser.ParseFile(fset, "", asValSpec, 0); err == nil && noBadNodes(f) {
+ decl := f.Decls[0].(*ast.GenDecl)
+ if len(decl.Specs) != 0 {
+ vs := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
+ return vs, nil
+ }
+ }
+
+ return nil, mainErr
+}
+
+type posOffset struct {
+ atLine, atCol int
+ offset int
+}
+
+func subPosOffsets(err error, offs ...posOffset) error {
+ list, ok := err.(scanner.ErrorList)
+ if !ok {
+ return err
+ }
+ for i, err := range list {
+ for _, off := range offs {
+ if err.Pos.Line != off.atLine {
+ continue
+ }
+ if err.Pos.Column < off.atCol {
+ continue
+ }
+ err.Pos.Column -= off.offset
+ }
+ list[i] = err
+ }
+ return list
+}
+
+type fullToken struct {
+ pos token.Position
+ tok token.Token
+ lit string
+}
+
+type caseStatus uint
+
+const (
+ caseNone caseStatus = iota
+ caseNeedBlock
+ caseHere
+)
+
+func tokenize(src []byte) ([]fullToken, error) {
+ var s scanner.Scanner
+ fset := token.NewFileSet()
+ file := fset.AddFile("", fset.Base(), len(src))
+
+ var err error
+ onError := func(pos token.Position, msg string) {
+ switch msg { // allow certain extra chars
+ case `illegal character U+0024 '$'`:
+ case `illegal character U+007E '~'`:
+ default:
+ err = fmt.Errorf("%v: %s", pos, msg)
+ }
+ }
+
+ // we will modify the input source under the scanner's nose to
+ // enable some features such as regexes.
+ s.Init(file, src, onError, scanner.ScanComments)
+
+ next := func() fullToken {
+ pos, tok, lit := s.Scan()
+ return fullToken{fset.Position(pos), tok, lit}
+ }
+
+ caseStat := caseNone
+
+ var toks []fullToken
+ for t := next(); t.tok != token.EOF; t = next() {
+ switch t.lit {
+ case "$": // continues below
+ case "switch", "select", "case":
+ if t.lit == "case" {
+ caseStat = caseNone
+ } else {
+ caseStat = caseNeedBlock
+ }
+ fallthrough
+ default: // regular Go code
+ if t.tok == token.LBRACE && caseStat == caseNeedBlock {
+ caseStat = caseHere
+ }
+ toks = append(toks, t)
+ continue
+ }
+ wt, err := tokenizeWildcard(t.pos, next)
+ if err != nil {
+ return nil, err
+ }
+ if caseStat == caseHere {
+ toks = append(toks, fullToken{wt.pos, token.IDENT, "case"})
+ }
+ toks = append(toks, wt)
+ if caseStat == caseHere {
+ toks = append(toks,
+ fullToken{wt.pos, token.COLON, ""},
+ fullToken{wt.pos, token.IDENT, "gogrep_body"})
+ }
+ }
+ return toks, err
+}
+
+type varInfo struct {
+ Name string
+ Seq bool
+}
+
+func tokenizeWildcard(pos token.Position, next func() fullToken) (fullToken, error) {
+ t := next()
+ any := false
+ if t.tok == token.MUL {
+ t = next()
+ any = true
+ }
+ wildName := encodeWildName(t.lit, any)
+ wt := fullToken{pos, token.IDENT, wildName}
+ if t.tok != token.IDENT {
+ return wt, fmt.Errorf("%v: $ must be followed by ident, got %v",
+ t.pos, t.tok)
+ }
+ return wt, nil
+}
+
+const wildSeparator = "ᐸᐳ"
+
+func isWildName(s string) bool {
+ return strings.HasPrefix(s, wildSeparator)
+}
+
+func encodeWildName(name string, any bool) string {
+ suffix := "v"
+ if any {
+ suffix = "a"
+ }
+ return wildSeparator + name + wildSeparator + suffix
+}
+
+func decodeWildName(s string) varInfo {
+ s = s[len(wildSeparator):]
+ nameEnd := strings.Index(s, wildSeparator)
+ name := s[:nameEnd+0]
+ s = s[nameEnd:]
+ s = s[len(wildSeparator):]
+ kind := s
+ return varInfo{Name: name, Seq: kind == "a"}
+}
+
+func decodeWildNode(n ast.Node) varInfo {
+ switch n := n.(type) {
+ case *ast.ExprStmt:
+ return decodeWildNode(n.X)
+ case *ast.Ident:
+ if isWildName(n.Name) {
+ return decodeWildName(n.Name)
+ }
+ }
+ return varInfo{}
+}
+
+type rangeClause struct {
+ X ast.Expr
+}
+
+type rangeHeader struct {
+ Node *ast.RangeStmt
+}
+
+func (*rangeClause) Pos() token.Pos { return 0 }
+func (*rangeClause) End() token.Pos { return 0 }
+
+func (*rangeHeader) Pos() token.Pos { return 0 }
+func (*rangeHeader) End() token.Pos { return 0 }
diff --git a/vendor/github.com/quasilyte/gogrep/slices.go b/vendor/github.com/quasilyte/gogrep/slices.go
new file mode 100644
index 000000000..13775a818
--- /dev/null
+++ b/vendor/github.com/quasilyte/gogrep/slices.go
@@ -0,0 +1,58 @@
+package gogrep
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+type NodeSlice interface {
+ At(i int) ast.Node
+ Len() int
+ slice(from, to int) NodeSlice
+ ast.Node
+}
+
+type (
+ ExprSlice []ast.Expr
+ stmtSlice []ast.Stmt
+ fieldSlice []*ast.Field
+ identSlice []*ast.Ident
+ specSlice []ast.Spec
+ declSlice []ast.Decl
+)
+
+func (l ExprSlice) Len() int { return len(l) }
+func (l ExprSlice) At(i int) ast.Node { return l[i] }
+func (l ExprSlice) slice(i, j int) NodeSlice { return l[i:j] }
+func (l ExprSlice) Pos() token.Pos { return l[0].Pos() }
+func (l ExprSlice) End() token.Pos { return l[len(l)-1].End() }
+
+func (l stmtSlice) Len() int { return len(l) }
+func (l stmtSlice) At(i int) ast.Node { return l[i] }
+func (l stmtSlice) slice(i, j int) NodeSlice { return l[i:j] }
+func (l stmtSlice) Pos() token.Pos { return l[0].Pos() }
+func (l stmtSlice) End() token.Pos { return l[len(l)-1].End() }
+
+func (l fieldSlice) Len() int { return len(l) }
+func (l fieldSlice) At(i int) ast.Node { return l[i] }
+func (l fieldSlice) slice(i, j int) NodeSlice { return l[i:j] }
+func (l fieldSlice) Pos() token.Pos { return l[0].Pos() }
+func (l fieldSlice) End() token.Pos { return l[len(l)-1].End() }
+
+func (l identSlice) Len() int { return len(l) }
+func (l identSlice) At(i int) ast.Node { return l[i] }
+func (l identSlice) slice(i, j int) NodeSlice { return l[i:j] }
+func (l identSlice) Pos() token.Pos { return l[0].Pos() }
+func (l identSlice) End() token.Pos { return l[len(l)-1].End() }
+
+func (l specSlice) Len() int { return len(l) }
+func (l specSlice) At(i int) ast.Node { return l[i] }
+func (l specSlice) slice(i, j int) NodeSlice { return l[i:j] }
+func (l specSlice) Pos() token.Pos { return l[0].Pos() }
+func (l specSlice) End() token.Pos { return l[len(l)-1].End() }
+
+func (l declSlice) Len() int { return len(l) }
+func (l declSlice) At(i int) ast.Node { return l[i] }
+func (l declSlice) slice(i, j int) NodeSlice { return l[i:j] }
+func (l declSlice) Pos() token.Pos { return l[0].Pos() }
+func (l declSlice) End() token.Pos { return l[len(l)-1].End() }