diff options
| author | Taras Madan <tarasmadan@google.com> | 2022-09-05 14:27:54 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-05 12:27:54 +0000 |
| commit | b2f2446b46bf02821d90ebedadae2bf7ae0e880e (patch) | |
| tree | 923cf42842918d6bebca1d6bbdc08abed54d274d /vendor/github.com/quasilyte/gogrep | |
| parent | e6654faff4bcca4be92e9a8596fd4b77f747c39e (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')
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 @@ + + + +[](https://pkg.go.dev/github.com/quasilyte/gogrep) +[](https://goreportcard.com/report/github.com/quasilyte/gogrep) + + +# 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() } |
