From 311fc13d9ee5796670a097d6b489adf4ad4a7c52 Mon Sep 17 00:00:00 2001 From: "Iskander (Alex) Sharipov" Date: Wed, 22 Dec 2021 18:09:26 +0300 Subject: [PATCH] all: use external gogrep, remove internal/gogrep (#319) Also: remove annoying codecov. We'll use something else. Fixes #318 --- .github/workflows/go.yml | 5 - README.md | 1 - go.mod | 4 +- go.sum | 5 +- internal/gogrep/compile.go | 1118 ------------------ internal/gogrep/compile_error_test.go | 62 - internal/gogrep/compile_test.go | 1058 ------------------ internal/gogrep/gen_operations.go | 348 ------ internal/gogrep/gogrep.go | 96 -- internal/gogrep/instruction_test.go | 18 - internal/gogrep/instructions.go | 116 -- internal/gogrep/match.go | 826 -------------- internal/gogrep/match_perf_test.go | 195 ---- internal/gogrep/match_test.go | 933 --------------- internal/gogrep/operation_string.go | 140 --- internal/gogrep/operations.gen.go | 1493 ------------------------- internal/gogrep/parse.go | 361 ------ internal/gogrep/slices.go | 58 - nodetag/nodetag.go | 278 ----- ruleguard/filters.go | 4 +- ruleguard/gorule.go | 4 +- ruleguard/ir_loader.go | 12 +- ruleguard/match_data.go | 2 +- ruleguard/ruleguard_test.go | 2 +- ruleguard/runner.go | 4 +- 25 files changed, 23 insertions(+), 7120 deletions(-) delete mode 100644 internal/gogrep/compile.go delete mode 100644 internal/gogrep/compile_error_test.go delete mode 100644 internal/gogrep/compile_test.go delete mode 100644 internal/gogrep/gen_operations.go delete mode 100644 internal/gogrep/gogrep.go delete mode 100644 internal/gogrep/instruction_test.go delete mode 100644 internal/gogrep/instructions.go delete mode 100644 internal/gogrep/match.go delete mode 100644 internal/gogrep/match_perf_test.go delete mode 100644 internal/gogrep/match_test.go delete mode 100644 internal/gogrep/operation_string.go delete mode 100644 internal/gogrep/operations.gen.go delete mode 100644 internal/gogrep/parse.go delete mode 100644 internal/gogrep/slices.go delete mode 100644 nodetag/nodetag.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 6845de3e..5bbb4ca6 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -17,11 +17,6 @@ {name: "Linter", run: "make lint"}, {name: "Test", run: "make test"}, {name: "Test release", run: "make test-release"}, - { - name: "Upload coverage", - uses: "codecov/codecov-action@v1", - "with": {token: "${{secrets.CODECOV_TOKEN}}", file: "./coverage.txt", fail_ci_if_error: false}, - }, ], }, }, diff --git a/README.md b/README.md index 34e2c11e..2d0e2373 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ ![Build Status](https://github.com/quasilyte/go-ruleguard/workflows/Merge/badge.svg) [![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/quasilyte/go-ruleguard)](https://pkg.go.dev/mod/github.com/quasilyte/go-ruleguard) [![Go Report Card](https://goreportcard.com/badge/github.com/quasilyte/go-ruleguard)](https://goreportcard.com/report/github.com/quasilyte/go-ruleguard) -![Code Coverage](https://codecov.io/gh/quasilyte/go-ruleguard/branch/master/graph/badge.svg) ![Logo](_docs/logo2.png) diff --git a/go.mod b/go.mod index 498f3590..ba6128ed 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,9 @@ go 1.15 require ( github.com/go-toolsmith/astcopy v1.0.0 - github.com/go-toolsmith/astequal v1.0.1 - github.com/google/go-cmp v0.5.2 + github.com/google/go-cmp v0.5.6 github.com/quasilyte/go-ruleguard/dsl v0.3.10 github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 + github.com/quasilyte/gogrep v0.0.0-20211222143908-ba25d0f7d6bf golang.org/x/tools v0.0.0-20201230224404-63754364767c ) diff --git a/go.sum b/go.sum index 2d9e8c2b..db467f16 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,9 @@ github.com/go-toolsmith/astequal v1.0.1 h1:JbSszi42Jiqu36Gnf363HWS9MTEAz67vTQLpo 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.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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= github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/dsl v0.3.10 h1:4tVlVVcBT+nNWoF+t/zrAMO13sHAqYotX1K12Gc8f8A= @@ -14,6 +15,8 @@ github.com/quasilyte/go-ruleguard/dsl v0.3.10/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQ github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 h1:CNooiryw5aisadVfzneSZPswRWvnVW8hF1bS/vo8ReI= github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= +github.com/quasilyte/gogrep v0.0.0-20211222143908-ba25d0f7d6bf h1:qDEThQwGIJN/ynrZdLgg4K8EwDRN7cFtRTJlxYtR7AY= +github.com/quasilyte/gogrep v0.0.0-20211222143908-ba25d0f7d6bf/go.mod h1:4t4AtVhIG+MC/9AZyzpdbEp0qn3LRMcJgsAa6BsGF+k= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/internal/gogrep/compile.go b/internal/gogrep/compile.go deleted file mode 100644 index 8fd6b782..00000000 --- a/internal/gogrep/compile.go +++ /dev/null @@ -1,1118 +0,0 @@ -package gogrep - -import ( - "fmt" - "go/ast" - "go/token" - - "github.com/quasilyte/go-ruleguard/internal/stdinfo" -) - -type compileError string - -func (e compileError) Error() string { return string(e) } - -type compiler struct { - prog *program - stringIndexes map[string]uint8 - ifaceIndexes map[interface{}]uint8 - strict bool - fset *token.FileSet - - info *PatternInfo - - insideStmtList bool -} - -func (c *compiler) Compile(fset *token.FileSet, root ast.Node, info *PatternInfo, strict bool) (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.fset = fset - c.strict = strict - 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.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) - 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) - if info.Seq { - c.compileWildIdent(ident, true) - } else if info.Name == "_" { - c.emitInstOp(opFieldNode) - } else { - 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.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(fn ast.Expr) { - if e, ok := fn.(*ast.SelectorExpr); ok { - if ident, ok := e.X.(*ast.Ident); ok && stdinfo.Packages[ident.Name] != "" { - c.emitInst(instruction{ - op: opSimpleSelectorExpr, - valueIndex: c.internString(e.Sel, e.Sel.String()), - }) - c.emitInst(instruction{ - op: opStdlibPkg, - valueIndex: c.internString(ident, ident.Name), - }) - return - } - } - - c.compileExpr(fn) -} - -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) - for _, elt := range n.List { - c.compileStmt(elt) - } - 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 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/internal/gogrep/compile_error_test.go b/internal/gogrep/compile_error_test.go deleted file mode 100644 index 99032256..00000000 --- a/internal/gogrep/compile_error_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package gogrep - -import ( - "fmt" - "go/token" - "strings" - "testing" -) - -func TestCompileError(t *testing.T) { - strict := func(s string) string { - return "STRICT " + s - } - isStrict := func(s string) bool { - return strings.HasPrefix(s, "STRICT ") - } - unwrapPattern := func(s string) string { - s = strings.TrimPrefix(s, "STRICT ") - return s - } - - intStatements := func() string { - parts := make([]string, 260) - for i := range parts { - parts[i] = fmt.Sprint(i) - } - return strings.Join(parts, ";") - }() - - tests := map[string]string{ - `$$`: `$ must be followed by ident, got ILLEGAL`, - `$`: `$ must be followed by ident, got EOF`, - - ``: `empty source code`, - "\t": `empty source code`, - - `foo)`: `expected statement, found ')'`, - `$x)`: `expected statement, found ')'`, - `$x(`: `expected operand, found '}'`, - `$*x)`: `expected statement, found ')'`, - "a\n$x)": `expected statement, found ')'`, - - `0xabci`: `can't convert 0xabci (IMAG) value`, - - intStatements: `implementation limitation: too many values`, - strict(intStatements): `implementation limitation: too many string values`, - } - - for input, want := range tests { - fset := token.NewFileSet() - testPattern := unwrapPattern(input) - _, _, err := Compile(fset, testPattern, isStrict(input)) - if err == nil { - t.Errorf("compile `%s`: expected error, got none", input) - continue - } - if !strings.Contains(err.Error(), want) { - t.Errorf("compile `%s`: error substring not found\nerror: %s\nsubstr: %s", - input, err, want) - } - } -} diff --git a/internal/gogrep/compile_test.go b/internal/gogrep/compile_test.go deleted file mode 100644 index c9d9759f..00000000 --- a/internal/gogrep/compile_test.go +++ /dev/null @@ -1,1058 +0,0 @@ -package gogrep - -import ( - "fmt" - "go/ast" - "go/parser" - "go/token" - "sort" - "strings" - "testing" - - "github.com/google/go-cmp/cmp" -) - -type compileTest struct { - input string - output []string -} - -func compileTestsFromMap(m map[string][]string) []compileTest { - result := make([]compileTest, 0, len(m)) - for input, output := range m { - result = append(result, compileTest{input: input, output: output}) - } - sort.Slice(result, func(i, j int) bool { - return result[i].input < result[j].input - }) - return result -} - -func TestCompileWildcard(t *testing.T) { - tests := compileTestsFromMap(map[string][]string{ - `$_`: {`Node`}, - `$x`: {`NamedNode x`}, - `$*_`: {`NodeSeq`}, - `$*x`: {`NamedNodeSeq x`}, - - `a.$x`: { - `SelectorExpr`, - ` • NamedNode x`, - ` • Ident a`, - }, - `$x.b`: { - `SimpleSelectorExpr b`, - ` • NamedNode x`, - }, - - `if $x != (nil) { $y }`: { - `IfStmt`, - ` • BinaryExpr !=`, - ` • • NamedNode x`, - ` • • ParenExpr`, - ` • • • Ident nil`, - ` • BlockStmt`, - ` • • NamedNode y`, - ` • • End`, - }, - `if $*_ {}`: { - `IfInitStmt`, - ` • OptNode`, - ` • Node`, - ` • BlockStmt`, - ` • • End`, - }, - `if $*_ {} else {}`: { - `IfInitElseStmt`, - ` • OptNode`, - ` • Node`, - ` • BlockStmt`, - ` • • End`, - ` • BlockStmt`, - ` • • End`, - }, - `if $*x {} else {}`: { - `IfNamedOptElseStmt x`, - ` • BlockStmt`, - ` • • End`, - ` • BlockStmt`, - ` • • End`, - }, - `if $*x {} else if $*x {}`: { - `IfNamedOptElseStmt x`, - ` • BlockStmt`, - ` • • End`, - ` • IfNamedOptStmt x`, - ` • • BlockStmt`, - ` • • • End`, - }, - `if $*x {}`: { - `IfNamedOptStmt x`, - ` • BlockStmt`, - ` • • End`, - }, - `if $_; cond {}`: { - `IfInitStmt`, - ` • Node`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - }, - `if $*_; cond {}`: { - `IfInitStmt`, - ` • OptNode`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - }, - `if $*x; cond {}`: { - `IfInitStmt`, - ` • NamedOptNode x`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - }, - - `func ($x typ) {}`: { - `FuncLit`, - ` • VoidFuncType`, - ` • • FieldList`, - ` • • • Field`, - ` • • • • NamedNode x`, - ` • • • • Ident typ`, - ` • • • End`, - ` • BlockStmt`, - ` • • End`, - }, - - `print($*_, x, $*_)`: { - `CallExpr`, - ` • Ident print`, - ` • ArgList`, - ` • • NodeSeq`, - ` • • Ident x`, - ` • • NodeSeq`, - ` • • End`, - }, - - `{ $*_; x; $*_ }`: { - `BlockStmt`, - ` • NodeSeq`, - ` • ExprStmt`, - ` • • Ident x`, - ` • NodeSeq`, - ` • End`, - }, - `{ $*head; x }`: { - `BlockStmt`, - ` • NamedNodeSeq head`, - ` • ExprStmt`, - ` • • Ident x`, - ` • End`, - }, - - `$l: if c {}`: { - `LabeledStmt`, - ` • NamedNode l`, - ` • IfStmt`, - ` • • Ident c`, - ` • • BlockStmt`, - ` • • • End`, - }, - - `goto $l`: { - `LabeledBranchStmt goto`, - ` • NamedNode l`, - }, - - `for $*_; $*_; $*_ {}`: { - `ForInitCondPostStmt`, - ` • OptNode`, - ` • OptNode`, - ` • OptNode`, - ` • BlockStmt`, - ` • • End`, - }, - - `const $x = $y`: { - `ConstDecl`, - ` • ValueInitSpec`, - ` • • NamedNode x`, - ` • • End`, - ` • • NamedNode y`, - ` • • End`, - ` • End`, - }, - - `const ($_ $_ = iota; $_; $*_)`: { - `ConstDecl`, - ` • TypedValueInitSpec`, - ` • • Node`, - ` • • End`, - ` • • Node`, - ` • • Ident iota`, - ` • • End`, - ` • Node`, - ` • NodeSeq`, - ` • End`, - }, - - `$_ int`: { - `TypedValueSpec`, - ` • Node`, - ` • End`, - ` • Ident int`, - }, - `$_ int = 5`: { - `TypedValueInitSpec`, - ` • Node`, - ` • End`, - ` • Ident int`, - ` • BasicLit 5`, - ` • End`, - }, - - `switch {$_}`: { - `SwitchStmt`, - ` • Node`, - ` • End`, - }, - - `switch $*_; x.(type) {}`: { - `TypeSwitchInitStmt`, - ` • OptNode`, - ` • ExprStmt`, - ` • • TypeSwitchAssertExpr`, - ` • • • Ident x`, - ` • End`, - }, - - `select {$*x}`: { - `SelectStmt`, - ` • NamedNodeSeq x`, - ` • End`, - }, - - `package $p`: { - `EmptyPackage`, - ` • NamedNode p`, - }, - - // $*_ in a place of a field list implies a field list of 0 or more fields. - // It can also match a field list of 1 element and nil. - `func $_() $*_ { $*_ }`: { - `FuncDecl`, - ` • Node`, - ` • FuncType`, - ` • • FieldList`, - ` • • • End`, - ` • • OptNode`, - ` • BlockStmt`, - ` • • NodeSeq`, - ` • • End`, - }, - - // $y in a place of a field list implies a field list of exactly 1 field. - `func $_($x $y) $y { return $x }`: { - `FuncDecl`, - ` • Node`, - ` • FuncType`, - ` • • FieldList`, - ` • • • Field`, - ` • • • • NamedNode x`, - ` • • • • NamedNode y`, - ` • • • End`, - ` • • NamedFieldNode y`, - ` • BlockStmt`, - ` • • ReturnStmt`, - ` • • • NamedNode x`, - ` • • • End`, - ` • • End`, - }, - - `func _($*_) {}`: { - `FuncDecl`, - ` • Ident _`, - ` • VoidFuncType`, - ` • • OptNode`, - ` • BlockStmt`, - ` • • End`, - }, - - `f($*_)`: { - `CallExpr`, - ` • Ident f`, - ` • ArgList`, - ` • • NodeSeq`, - ` • • End`, - }, - - `f(1, $*_)`: { - `CallExpr`, - ` • Ident f`, - ` • ArgList`, - ` • • BasicLit 1`, - ` • • NodeSeq`, - ` • • End`, - }, - - `f($_)`: { - `NonVariadicCallExpr`, - ` • Ident f`, - ` • SimpleArgList 1`, - ` • • Node`, - }, - - `var x int; if true { f() }`: { - `MultiStmt`, - ` • DeclStmt`, - ` • • VarDecl`, - ` • • • TypedValueSpec`, - ` • • • • Ident x`, - ` • • • • End`, - ` • • • • Ident int`, - ` • • • End`, - ` • IfStmt`, - ` • • Ident true`, - ` • • BlockStmt`, - ` • • • ExprStmt`, - ` • • • • NonVariadicCallExpr`, - ` • • • • • Ident f`, - ` • • • • • SimpleArgList 0`, - ` • • • End`, - ` • End`, - }, - - `struct{$*_; Foo; $*_}`: { - `StructType`, - ` • FieldList`, - ` • • NodeSeq`, - ` • • UnnamedField`, - ` • • • Ident Foo`, - ` • • NodeSeq`, - ` • • End`, - }, - - `func $_($*_) $_ { $*_ }`: { - `FuncDecl`, - ` • Node`, - ` • FuncType`, - ` • • OptNode`, - ` • • FieldNode`, - ` • BlockStmt`, - ` • • NodeSeq`, - ` • • End`, - }, - - `s[$*_:$*_]`: { - `SliceFromToExpr`, - ` • Ident s`, - ` • OptNode`, - ` • OptNode`, - }, - - `s[$*_:]`: { - `SliceFromExpr`, - ` • Ident s`, - ` • OptNode`, - }, - - `const $_ $*_ = iota`: { - `ConstDecl`, - ` • TypedValueInitSpec`, - ` • • Node`, - ` • • End`, - ` • • OptNode`, - ` • • Ident iota`, - ` • • End`, - ` • End`, - }, - }) - - for i := range tests { - test := tests[i] - t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) { - input := test.input - want := test.output - fset := token.NewFileSet() - p, _, err := Compile(fset, input, false) - if err != nil { - t.Errorf("compile `%s`: %v", input, err) - return - } - have := formatProgram(p.m.prog) - if diff := cmp.Diff(have, want); diff != "" { - t.Errorf("compile `%s` (+want -have):\n%s", input, diff) - fmt.Printf("Output:\n") - for _, line := range have { - fmt.Printf("`%s`,\n", line) - } - return - } - }) - } -} - -func TestCompile(t *testing.T) { - tests := compileTestsFromMap(map[string][]string{ - `package p;`: { - `EmptyPackage`, - ` • Ident p`, - }, - - `var ()`: { - `VarDecl`, - ` • End`, - }, - `type foo = int`: { - `TypeDecl`, - ` • TypeAliasSpec`, - ` • • Ident foo`, - ` • • Ident int`, - ` • End`, - }, - `type (a int64; b string)`: { - `TypeDecl`, - ` • TypeSpec`, - ` • • Ident a`, - ` • • Ident int64`, - ` • TypeSpec`, - ` • • Ident b`, - ` • • Ident string`, - ` • End`, - }, - - `10`: {`BasicLit 10`}, - `2.4`: {`BasicLit 2.4`}, - `"foo"`: {`BasicLit "foo"`}, - `'a'`: {`BasicLit 97`}, - `'\n'`: {`BasicLit 10`}, - `'✓'`: {`BasicLit 10003`}, - - `*x`: { - `StarExpr`, - ` • Ident x`, - }, - `+x`: { - `UnaryExpr +`, - ` • Ident x`, - }, - `-x`: { - `UnaryExpr -`, - ` • Ident x`, - }, - `((x))`: { - `ParenExpr`, - ` • ParenExpr`, - ` • • Ident x`, - }, - - `[]func() int{}`: { - `TypedCompositeLit`, - ` • SliceType`, - ` • • FuncType`, - ` • • • FieldList`, - ` • • • • End`, - ` • • • FieldList`, - ` • • • • UnnamedField`, - ` • • • • • Ident int`, - ` • • • • End`, - ` • End`, - }, - - `func () {}`: { - `FuncLit`, - ` • VoidFuncType`, - ` • • FieldList`, - ` • • • End`, - ` • BlockStmt`, - ` • • End`, - }, - `func(xs ...int) {}`: { - `FuncLit`, - ` • VoidFuncType`, - ` • • FieldList`, - ` • • • SimpleField xs`, - ` • • • • TypedEllipsis`, - ` • • • • • Ident int`, - ` • • • End`, - ` • BlockStmt`, - ` • • End`, - }, - `func(x, y int, z int) (string, string) {}`: { - `FuncLit`, - ` • FuncType`, - ` • • FieldList`, - ` • • • MultiField`, - ` • • • • Ident x`, - ` • • • • Ident y`, - ` • • • • End`, - ` • • • • Ident int`, - ` • • • SimpleField z`, - ` • • • • Ident int`, - ` • • • End`, - ` • • FieldList`, - ` • • • UnnamedField`, - ` • • • • Ident string`, - ` • • • UnnamedField`, - ` • • • • Ident string`, - ` • • • End`, - ` • BlockStmt`, - ` • • End`, - }, - - `1 + 2`: { - `BinaryExpr +`, - ` • BasicLit 1`, - ` • BasicLit 2`, - }, - `1 - (x)`: { - `BinaryExpr -`, - ` • BasicLit 1`, - ` • ParenExpr`, - ` • • Ident x`, - }, - - `f(1, 2)`: { - `NonVariadicCallExpr`, - ` • Ident f`, - ` • SimpleArgList 2`, - ` • • BasicLit 1`, - ` • • BasicLit 2`, - }, - - `f(g(), xs...)`: { - `VariadicCallExpr`, - ` • Ident f`, - ` • SimpleArgList 2`, - ` • • NonVariadicCallExpr`, - ` • • • Ident g`, - ` • • • SimpleArgList 0`, - ` • • Ident xs`, - }, - - `x[0]`: { - `IndexExpr`, - ` • Ident x`, - ` • BasicLit 0`, - }, - - `s[:]`: { - `SliceExpr`, - ` • Ident s`, - }, - `s[from:]`: { - `SliceFromExpr`, - ` • Ident s`, - ` • Ident from`, - }, - `s[:to]`: { - `SliceToExpr`, - ` • Ident s`, - ` • Ident to`, - }, - `s[from:to]`: { - `SliceFromToExpr`, - ` • Ident s`, - ` • Ident from`, - ` • Ident to`, - }, - `s[:to:max]`: { - `SliceToCapExpr`, - ` • Ident s`, - ` • Ident to`, - ` • Ident max`, - }, - `s[from:to:max]`: { - `SliceFromToCapExpr`, - ` • Ident s`, - ` • Ident from`, - ` • Ident to`, - ` • Ident max`, - }, - - `([2]int)(x)`: { - `NonVariadicCallExpr`, - ` • ParenExpr`, - ` • • ArrayType`, - ` • • • BasicLit 2`, - ` • • • Ident int`, - ` • SimpleArgList 1`, - ` • • Ident x`, - }, - `([]int)(x)`: { - `NonVariadicCallExpr`, - ` • ParenExpr`, - ` • • SliceType`, - ` • • • Ident int`, - ` • SimpleArgList 1`, - ` • • Ident x`, - }, - - `[]int{1, 2}`: { - `TypedCompositeLit`, - ` • SliceType`, - ` • • Ident int`, - ` • BasicLit 1`, - ` • BasicLit 2`, - ` • End`, - }, - `[][]int{{1, 2}, {3}}`: { - `TypedCompositeLit`, - ` • SliceType`, - ` • • SliceType`, - ` • • • Ident int`, - ` • CompositeLit`, - ` • • BasicLit 1`, - ` • • BasicLit 2`, - ` • • End`, - ` • CompositeLit`, - ` • • BasicLit 3`, - ` • • End`, - ` • End`, - }, - - `[...]int{5: 1}`: { - `TypedCompositeLit`, - ` • ArrayType`, - ` • • Ellipsis`, - ` • • Ident int`, - ` • KeyValueExpr`, - ` • • BasicLit 5`, - ` • • BasicLit 1`, - ` • End`, - }, - `map[int]string{}`: { - `TypedCompositeLit`, - ` • MapType`, - ` • • Ident int`, - ` • • Ident string`, - ` • End`, - }, - - `go f()`: { - `GoStmt`, - ` • NonVariadicCallExpr`, - ` • • Ident f`, - ` • • SimpleArgList 0`, - }, - - `defer f()`: { - `DeferStmt`, - ` • NonVariadicCallExpr`, - ` • • Ident f`, - ` • • SimpleArgList 0`, - }, - - `ch <- 1`: { - `SendStmt`, - ` • Ident ch`, - ` • BasicLit 1`, - }, - - `x.y.z`: { - `SimpleSelectorExpr z`, - ` • SimpleSelectorExpr y`, - ` • • Ident x`, - }, - - `x.(int)`: { - `TypeAssertExpr`, - ` • Ident x`, - ` • Ident int`, - }, - - `;`: {`EmptyStmt`}, - - `x++`: { - `IncDecStmt ++`, - ` • Ident x`, - }, - `x--`: { - `IncDecStmt --`, - ` • Ident x`, - }, - - `{ f(); g(); }`: { - `BlockStmt`, - ` • ExprStmt`, - ` • • NonVariadicCallExpr`, - ` • • • Ident f`, - ` • • • SimpleArgList 0`, - ` • ExprStmt`, - ` • • NonVariadicCallExpr`, - ` • • • Ident g`, - ` • • • SimpleArgList 0`, - ` • End`, - }, - - `if cond {}`: { - `IfStmt`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - }, - `if init; cond {}`: { - `IfInitStmt`, - ` • ExprStmt`, - ` • • Ident init`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - }, - `if cond {} else { f() }`: { - `IfElseStmt`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - ` • BlockStmt`, - ` • • ExprStmt`, - ` • • • NonVariadicCallExpr`, - ` • • • • Ident f`, - ` • • • • SimpleArgList 0`, - ` • • End`, - }, - `if cond {} else if cond2 { f() } else {}`: { - `IfElseStmt`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - ` • IfElseStmt`, - ` • • Ident cond2`, - ` • • BlockStmt`, - ` • • • ExprStmt`, - ` • • • • NonVariadicCallExpr`, - ` • • • • • Ident f`, - ` • • • • • SimpleArgList 0`, - ` • • • End`, - ` • • BlockStmt`, - ` • • • End`, - }, - `if init1; cond {} else if init2; cond2 { f() } else {}`: { - `IfInitElseStmt`, - ` • ExprStmt`, - ` • • Ident init1`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - ` • IfInitElseStmt`, - ` • • ExprStmt`, - ` • • • Ident init2`, - ` • • Ident cond2`, - ` • • BlockStmt`, - ` • • • ExprStmt`, - ` • • • • NonVariadicCallExpr`, - ` • • • • • Ident f`, - ` • • • • • SimpleArgList 0`, - ` • • • End`, - ` • • BlockStmt`, - ` • • • End`, - }, - - `return 1, 2`: { - `ReturnStmt`, - ` • BasicLit 1`, - ` • BasicLit 2`, - ` • End`, - }, - - `break`: {`BranchStmt break`}, - `continue`: {`BranchStmt continue`}, - `fallthrough`: {`BranchStmt fallthrough`}, - `break l`: {`SimpleLabeledBranchStmt break l`}, - `continue l`: {`SimpleLabeledBranchStmt continue l`}, - `goto l`: {`SimpleLabeledBranchStmt goto l`}, - - `foo: x`: { - `SimpleLabeledStmt foo`, - ` • ExprStmt`, - ` • • Ident x`, - }, - - `x = y`: { - `AssignStmt =`, - ` • Ident x`, - ` • Ident y`, - }, - `x := y`: { - `AssignStmt :=`, - ` • Ident x`, - ` • Ident y`, - }, - `x, y := f()`: { - `MultiAssignStmt :=`, - ` • Ident x`, - ` • Ident y`, - ` • End`, - ` • NonVariadicCallExpr`, - ` • • Ident f`, - ` • • SimpleArgList 0`, - ` • End`, - }, - - `(chan int)(nil)`: { - `NonVariadicCallExpr`, - ` • ParenExpr`, - ` • • ChanType send recv`, - ` • • • Ident int`, - ` • SimpleArgList 1`, - ` • • Ident nil`, - }, - `(chan<- int)(nil)`: { - `NonVariadicCallExpr`, - ` • ParenExpr`, - ` • • ChanType send`, - ` • • • Ident int`, - ` • SimpleArgList 1`, - ` • • Ident nil`, - }, - `(<-chan int)(nil)`: { - `NonVariadicCallExpr`, - ` • ParenExpr`, - ` • • ChanType recv`, - ` • • • Ident int`, - ` • SimpleArgList 1`, - ` • • Ident nil`, - }, - - `for range xs {}`: { - `RangeStmt`, - ` • Ident xs`, - ` • BlockStmt`, - ` • • End`, - }, - `for i := range xs {}`: { - `RangeKeyStmt :=`, - ` • Ident i`, - ` • Ident xs`, - ` • BlockStmt`, - ` • • End`, - }, - `for i = range xs {}`: { - `RangeKeyStmt =`, - ` • Ident i`, - ` • Ident xs`, - ` • BlockStmt`, - ` • • End`, - }, - `for i, x := range xs {}`: { - `RangeKeyValueStmt :=`, - ` • Ident i`, - ` • Ident x`, - ` • Ident xs`, - ` • BlockStmt`, - ` • • End`, - }, - `for i, x = range xs {}`: { - `RangeKeyValueStmt =`, - ` • Ident i`, - ` • Ident x`, - ` • Ident xs`, - ` • BlockStmt`, - ` • • End`, - }, - - `for {}`: { - `ForStmt`, - ` • BlockStmt`, - ` • • End`, - }, - `for ;; {}`: { - `ForStmt`, - ` • BlockStmt`, - ` • • End`, - }, - `for ;; post {}`: { - `ForPostStmt`, - ` • ExprStmt`, - ` • • Ident post`, - ` • BlockStmt`, - ` • • End`, - }, - `for cond {}`: { - `ForCondStmt`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - }, - `for ; cond; {}`: { - `ForCondStmt`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - }, - `for ; cond; post {}`: { - `ForCondPostStmt`, - ` • Ident cond`, - ` • ExprStmt`, - ` • • Ident post`, - ` • BlockStmt`, - ` • • End`, - }, - `for init; ; {}`: { - `ForInitStmt`, - ` • ExprStmt`, - ` • • Ident init`, - ` • BlockStmt`, - ` • • End`, - }, - `for init; ; post {}`: { - `ForInitPostStmt`, - ` • ExprStmt`, - ` • • Ident init`, - ` • ExprStmt`, - ` • • Ident post`, - ` • BlockStmt`, - ` • • End`, - }, - `for init; cond; {}`: { - `ForInitCondStmt`, - ` • ExprStmt`, - ` • • Ident init`, - ` • Ident cond`, - ` • BlockStmt`, - ` • • End`, - }, - `for init; cond; post {}`: { - `ForInitCondPostStmt`, - ` • ExprStmt`, - ` • • Ident init`, - ` • Ident cond`, - ` • ExprStmt`, - ` • • Ident post`, - ` • BlockStmt`, - ` • • End`, - }, - - `switch x.(type) {}`: { - `TypeSwitchStmt`, - ` • ExprStmt`, - ` • • TypeSwitchAssertExpr`, - ` • • • Ident x`, - ` • End`, - }, - - `switch x := y.(type) {}`: { - `TypeSwitchStmt`, - ` • AssignStmt :=`, - ` • • Ident x`, - ` • • TypeSwitchAssertExpr`, - ` • • • Ident y`, - ` • End`, - }, - - `switch {case 1, 2: f(); default: g() }`: { - `SwitchStmt`, - ` • CaseClause`, - ` • • BasicLit 1`, - ` • • BasicLit 2`, - ` • • End`, - ` • • ExprStmt`, - ` • • • NonVariadicCallExpr`, - ` • • • • Ident f`, - ` • • • • SimpleArgList 0`, - ` • • End`, - ` • DefaultCaseClause`, - ` • • ExprStmt`, - ` • • • NonVariadicCallExpr`, - ` • • • • Ident g`, - ` • • • • SimpleArgList 0`, - ` • • End`, - ` • End`, - }, - - `fmt.Println(5, 6)`: { - `NonVariadicCallExpr`, - ` • SimpleSelectorExpr Println`, - ` • • StdlibPkg fmt`, - ` • SimpleArgList 2`, - ` • • BasicLit 5`, - ` • • BasicLit 6`, - }, - - `x = fmt.Sprint(y)`: { - `AssignStmt =`, - ` • Ident x`, - ` • NonVariadicCallExpr`, - ` • • SimpleSelectorExpr Sprint`, - ` • • • StdlibPkg fmt`, - ` • • SimpleArgList 1`, - ` • • • Ident y`, - }, - - `const (x = 1; y = 2)`: { - `ConstDecl`, - ` • ValueInitSpec`, - ` • • Ident x`, - ` • • End`, - ` • • BasicLit 1`, - ` • • End`, - ` • ValueInitSpec`, - ` • • Ident y`, - ` • • End`, - ` • • BasicLit 2`, - ` • • End`, - ` • End`, - }, - - `const (x = iota; y)`: { - `ConstDecl`, - ` • ValueInitSpec`, - ` • • Ident x`, - ` • • End`, - ` • • Ident iota`, - ` • • End`, - ` • ValueSpec`, - ` • • Ident y`, - ` • End`, - }, - }) - - for i := range tests { - test := tests[i] - t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) { - input := test.input - want := test.output - fset := token.NewFileSet() - n := testParseNode(t, fset, input) - var c compiler - info := newPatternInfo() - p, err := c.Compile(fset, n, &info, false) - if err != nil { - t.Errorf("compile `%s`: %v", input, err) - return - } - - have := formatProgram(p) - if diff := cmp.Diff(have, want); diff != "" { - t.Errorf("compile `%s` (+want -have):\n%s", input, diff) - fmt.Printf("Output:\n") - for _, line := range have { - fmt.Printf("`%s`,\n", line) - } - return - } - }) - } -} - -func testParseNode(t testing.TB, fset *token.FileSet, s string) ast.Node { - if strings.HasPrefix(s, "package ") { - file, err := parser.ParseFile(fset, "string", s, 0) - if err != nil { - t.Fatalf("parse `%s`: %v", s, err) - } - return file - } - source := `package p; func _() { ` + s + ` }` - file, err := parser.ParseFile(fset, "string", source, 0) - if err != nil { - t.Fatalf("parse `%s`: %v", s, err) - } - fn := file.Decls[0].(*ast.FuncDecl) - n := fn.Body.List[0] - if e, ok := n.(*ast.ExprStmt); ok { - return e.X - } - return n -} diff --git a/internal/gogrep/gen_operations.go b/internal/gogrep/gen_operations.go deleted file mode 100644 index d01d55b4..00000000 --- a/internal/gogrep/gen_operations.go +++ /dev/null @@ -1,348 +0,0 @@ -// +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: "StdlibPkg", tag: "Ident", valueIndex: "strings | package name"}, - - {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: "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: "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/go-ruleguard/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/internal/gogrep/gogrep.go b/internal/gogrep/gogrep.go deleted file mode 100644 index ea054f33..00000000 --- a/internal/gogrep/gogrep.go +++ /dev/null @@ -1,96 +0,0 @@ -package gogrep - -import ( - "go/ast" - "go/token" - "go/types" - - "github.com/quasilyte/go-ruleguard/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 MatcherState struct { - Types *types.Info - - // node values recorded by name, excluding "_" (used only by the - // actual matching phase) - capture []CapturedNode - - pc int -} - -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 -} - -func Compile(fset *token.FileSet, src string, strict bool) (*Pattern, PatternInfo, error) { - info := newPatternInfo() - n, err := parseExpr(fset, src) - if err != nil { - return nil, info, err - } - var c compiler - prog, err := c.Compile(fset, n, &info, strict) - if err != nil { - return nil, info, err - } - m := newMatcher(prog) - return &Pattern{m: m}, info, nil -} - -func newPatternInfo() PatternInfo { - return PatternInfo{ - Vars: map[string]struct{}{}, - } -} diff --git a/internal/gogrep/instruction_test.go b/internal/gogrep/instruction_test.go deleted file mode 100644 index 31aadd3a..00000000 --- a/internal/gogrep/instruction_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package gogrep - -import ( - "math/bits" - "testing" - "unsafe" -) - -func TestInstructionSize(t *testing.T) { - if bits.UintSize != 64 { - t.Skip("not 64-bit platform") - } - wantSize := 3 - haveSize := int(unsafe.Sizeof(instruction{})) - if wantSize != haveSize { - t.Errorf("sizeof(instruction): have %d, want %d", haveSize, wantSize) - } -} diff --git a/internal/gogrep/instructions.go b/internal/gogrep/instructions.go deleted file mode 100644 index 9f4f72d8..00000000 --- a/internal/gogrep/instructions.go +++ /dev/null @@ -1,116 +0,0 @@ -package gogrep - -import ( - "fmt" - "go/ast" - "go/token" - "strings" -) - -type bitmap64 uint64 - -func (m bitmap64) IsSet(pos int) bool { - return m&(1<= 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 opStdlibPkg: - 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 && m.stringValue(inst) == pkgName.Imported().Name() && - pkgName.Imported().Path() == stdinfo.Packages[pkgName.Imported().Name()] - - 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 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) (ast.Node, 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 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/internal/gogrep/match_perf_test.go b/internal/gogrep/match_perf_test.go deleted file mode 100644 index 61a8ad14..00000000 --- a/internal/gogrep/match_perf_test.go +++ /dev/null @@ -1,195 +0,0 @@ -package gogrep - -import ( - "go/token" - "strings" - "testing" -) - -func BenchmarkMatch(b *testing.B) { - tests := []struct { - name string - pat string - input string - }{ - { - name: `failFast`, - pat: `f()`, - input: `[]int{}`, - }, - { - name: `failCall`, - pat: `f(1, 2, 3, 4)`, - input: `f(1, 2, 3, _)`, - }, - { - name: `failCallFast`, - pat: `f(1, 2, 3)`, - input: `f()`, - }, - { - name: `assign`, - pat: `x := 1`, - input: `x := 1`, - }, - { - name: `assignMulti`, - pat: `$*_ = f()`, - input: `x, y = f()`, - }, - { - name: `simpleLit`, - pat: `true`, - input: `true`, - }, - { - name: `simpleBinaryOp`, - pat: `1 + 2`, - input: `1 + 2`, - }, - { - name: `simpleSelectorExpr`, - pat: `x.y.z`, - input: `x.y.z`, - }, - { - name: `simpleCall`, - pat: `f(1, 2)`, - input: `f(1, 2)`, - }, - { - name: `selectorExpr`, - pat: `a.$x`, - input: `a.b.c`, - }, - { - name: `sliceExpr`, - pat: `s[$x:]`, - input: `s[1:]`, - }, - { - name: `any`, - pat: `$_`, - input: `x + y`, - }, - { - name: `anyCall`, - pat: `$_($*_)`, - input: `f(1, "2", '3',)`, - }, - { - name: `ifStmt`, - pat: `if cond { $y }`, - input: `if cond { return nil }`, - }, - { - name: `optStmt1`, - pat: `if $*_ {}`, - input: `if init; f() {}`, - }, - { - name: `optStmt2`, - pat: `if $*_; cond {}`, - input: `if cond {}`, - }, - { - name: `namedOptStmt1`, - pat: `if $*x {}; if $*x {}`, - input: `{ if init; cond {}; if init; cond {} }`, - }, - { - name: `namedOptStmt2`, - pat: `if $*x; cond {}; if $*x; cond {}`, - input: `{ if init; cond {}; if init; cond {} }`, - }, - { - name: `branchStmt`, - pat: `break foo`, - input: `break foo`, - }, - { - name: `multiStmt`, - pat: `x; y`, - input: `{ f(); x; y; z }`, - }, - { - name: `multiExpr`, - pat: `x, y`, - input: `f(_, x, _, _, x, y, _)`, - }, - { - name: `variadicCall`, - pat: `f(xs...)`, - input: `f(xs...)`, - }, - { - name: `capture1`, - pat: `+$x`, - input: `+50`, - }, - { - name: `capture2`, - pat: `$x + $y`, - input: `x + 4`, - }, - { - name: `capture8`, - pat: `f($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8)`, - input: `f(1, 2, 3, 4, 5, 6, 7, 8)`, - }, - { - name: `capture2same`, - pat: `$x + $x`, - input: `a + a`, - }, - { - name: `capture8same`, - pat: `f($x, $x, $x, $x, $x, $x, $x, $x)`, - input: `f(1, 1, 1, 1, 1, 1, 1, 1)`, - }, - { - name: `captureBacktrackLeft`, - pat: `f($*xs, $y)`, - input: `f(1, 2, 3, 4, 5, 6)`, - }, - { - name: `captureBacktrackRight`, - pat: `f($x, $*ys)`, - input: `f(1, 2, 3, 4, 5, 6)`, - }, - } - - for i := range tests { - test := tests[i] - b.Run(test.name, func(b *testing.B) { - state := NewMatcherState() - - fset := token.NewFileSet() - pat, _, err := Compile(fset, test.pat, true) - if err != nil { - b.Errorf("parse `%s`: %v", test.pat, err) - return - } - target := testParseNode(b, token.NewFileSet(), test.input) - if err != nil { - b.Errorf("parse target `%s`: %v", test.input, err) - return - } - if !strings.HasPrefix(test.name, "fail") { - matches := 0 - testAllMatches(pat, &state, target, func(m MatchData) { - matches++ - }) - if matches == 0 { - b.Fatal("matching failed") - } - } - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - testAllMatches(pat, &state, target, func(m MatchData) {}) - } - }) - } -} diff --git a/internal/gogrep/match_test.go b/internal/gogrep/match_test.go deleted file mode 100644 index 829dece0..00000000 --- a/internal/gogrep/match_test.go +++ /dev/null @@ -1,933 +0,0 @@ -package gogrep - -import ( - "fmt" - "go/ast" - "go/token" - "strings" - "testing" -) - -// FIXME: find test case duplicates. - -func TestMatch(t *testing.T) { - strict := func(s string) string { - return "STRICT " + s - } - isStrict := func(s string) bool { - return strings.HasPrefix(s, "STRICT ") - } - unwrapPattern := func(s string) string { - s = strings.TrimPrefix(s, "STRICT ") - return s - } - - tests := []struct { - pat string - numMatches int - input string - }{ - {`123`, 1, `123`}, - {`123`, 0, `12`}, - {`2.71828i`, 1, `2.71828i`}, - {`2.71828i`, 0, `2.71820i`}, - {`'a'`, 1, `'a'`}, - {`'a'`, 0, `'b'`}, - {`'✓'`, 1, `'✓'`}, - {`"ab"`, 1, `"ab"`}, - {`"ab"`, 0, `"foo"`}, - {`true`, 1, `true`}, - {`false`, 0, `true`}, - - {`($x)`, 1, `(a + b)`}, - {`($x)`, 0, `a + b`}, - - {`$x`, 1, `123`}, - {`$_`, 1, `123`}, - - {`;`, 1, `;`}, - {`;`, 0, `1`}, - - // In strict mode, differently spelled literals won't match. - {strict(`"a"`), 1, `"a"`}, - {strict("`a`"), 1, "`a`"}, - {strict(`"a"`), 0, "`a`"}, - {strict("`a`"), 0, `"a"`}, - {strict("`a`"), 0, `"b"`}, - {strict(`'✓'`), 0, `'\u2713'`}, - {strict(`'\n'`), 0, `'\x0a'`}, - {strict(`0x0`), 0, `0`}, - {strict(`2748i`), 1, `2748i`}, - {strict(`2748i`), 0, `2740i`}, - {strict(`4.5`), 1, `4.5`}, - {strict(`0.01`), 0, `.01`}, - - // In non-strict mode, these literals can match. - {`"aa"`, 1, "`aa`"}, - {`'\n'`, 1, `'\x0a'`}, - {`0x0`, 1, `0`}, - {`3`, 1, `0b11`}, - {`0.01`, 1, `.01`}, - {`'a'`, 0, `"a"`}, - {`'✓'`, 0, `10003`}, - {`'✓'`, 1, `'\u2713'`}, - - // Binary op. - {strict(`1 + 2`), 1, `1 + 2`}, - {`$_`, 3, `1 * 2`}, - {`x == y`, 1, `x == y`}, - {`x == y`, 0, `x == x`}, - {`x == y`, 0, `x != y`}, - {`x != y`, 1, `x != y`}, - {`$x + $x`, 1, `x + x`}, - {`$x + $x`, 0, `x + y`}, - {`$x + $x`, 0, `x + 0`}, - {`$x + $x`, 0, `foo(a) + foo(b)`}, - {`$x + $x`, 1, `foo(a) + foo(a)`}, - - // Unary op. - {`+x`, 1, `+x`}, - {`+x`, 0, `+y`}, - {`-someConst`, 1, `- someConst`}, - {`*someVar`, 1, `* someVar`}, - {`-someConst`, 0, `someConst`}, - {`*someVar`, 0, `someVar`}, - - // Forcing node to be a statement. - {`append($*_);`, 1, `{ f(); append(x, a) }`}, - {`append($*_);`, 0, `{ f(); x = append(x, a) }`}, - - // Call expr. - {`f(1, 2, "foo")`, 1, `f(1, 2, "foo")`}, - {`f(1, 2, "foo")`, 0, `g(1, 2, "foo")`}, - {`f(1, 2, "foo")`, 0, `f(1, 2, "bar")`}, - {`f(1, 2, "foo")`, 0, `f(1, 2)`}, - {`f(1, 2)`, 0, `f(1, 2, "foo")`}, - {`print($*x)`, 1, `print()`}, - {`print($*x)`, 1, `print(a, b)`}, - {`print($*_)`, 1, `print()`}, - {`print($*_)`, 1, `print(a, b)`}, - {`print($*x, $y, $*z)`, 0, `print()`}, - {`print($*x, $y, $*z)`, 1, `print(a)`}, - {`print($*x, $y, $*z)`, 1, `print(a, b, c)`}, - {`print($*_, x, $*_)`, 1, `print(x)`}, - {`print($*_, f(), $*_)`, 1, `print(f())`}, - {`print($*_, f(), $*_)`, 1, `print(1, f())`}, - {`print($*_, f(), $*_)`, 1, `print(1, 2, f(), 3)`}, - {`print($*_, f(), $*_)`, 1, `print(f(), 1)`}, - {`print($*_, f($*args), $*_)`, 1, `print(f())`}, - {`print($*_, f($*args), $*_)`, 1, `print(f(1))`}, - {`print($*_, f($*args), $*_)`, 1, `print(f(1, 2), 3)`}, - {`f(1, $*_, 2)`, 1, `f(1, 2)`}, - {`f(1, $*_, 2)`, 1, `f(1, "x", 2)`}, - {`f(1, $*_, 2)`, 1, `f(1, "x", "y", 2)`}, - {`f(1, $*_, 2)`, 0, `f(1, "x", "y")`}, - {`f(1, $*_, 2)`, 0, `f(1)`}, - {`foo($x, $x)`, 0, `foo(1, 2)`}, - {`foo($_, $_)`, 1, `foo(1, 2)`}, - {`foo($x, $y, $y)`, 1, `foo(1, 2, 2)`}, - {`foo($x, $y, $y)`, 0, `foo(1, 2, 3)`}, - {`$x.Method()`, 1, `a.Method()`}, - {`$x.Method()`, 1, `a.b.Method()`}, - {`$x.Method()`, 0, `a.b.Method`}, - {`$x.Method()`, 0, `a.b.Method2()`}, - {`x.Method()`, 0, `y.Method2()`}, - {`$x.Method()`, 0, `a.Method(1)`}, - {`f($*_)`, 1, `f(xs...)`}, - {`f($*_)`, 1, `f(1, xs...)`}, - {`f($*_)`, 1, `f(1, 2, xs...)`}, - {`f($_, $*_)`, 1, `f(1, 2, xs...)`}, - {`f($*_, $_)`, 0, `f(1, 2, xs...)`}, - {`f($*_, xs)`, 0, `f(1, 2, xs...)`}, - {`f($*_, xs...)`, 1, `f(1, 2, xs...)`}, - - // Selector expr. - {`$x.Field`, 1, `a.Field`}, - {`$x.Field`, 1, `b.Field`}, - {`$x.Field`, 0, `a.field`}, - {`a.b`, 1, `a.b.c`}, - {`b.c`, 0, `a.b.c`}, - {`$x.c`, 1, `a.b.c`}, - {`a.$x`, 1, `a.b.c`}, - - // Index expr. - {`$x[0][1]`, 1, `x[0][1]`}, - {`$x[0][1]`, 1, `x[10][0][1]`}, - {`$x[0][1]`, 0, `x[0][10]`}, - {`$x[len($x)-1]`, 1, `a[len(a)-1]`}, - {`$x[len($x)-1]`, 0, `a[len(b)-1]`}, - - // Slice expr. - {`x[:]`, 1, `x[:]`}, - {`x[:]`, 0, `y[:]`}, - {`x[:]`, 0, `x[1:]`}, - {`x[:]`, 0, `x[:1]`}, - {`x[:y]`, 1, `x[:y]`}, - {`x[:y]`, 0, `x[:z]`}, - {`x[:y]`, 0, `z[:y]`}, - {`x[:y]`, 0, `x[:y:z]`}, - {`$x[:$y]`, 1, `a[:1]`}, - {`$x[:$y]`, 0, `a[:]`}, - {`x[y:]`, 1, `x[y:]`}, - {`x[y:]`, 0, `z[y:]`}, - {`x[y:]`, 0, `x[z:]`}, - {`$x[$y:]`, 1, `a[1:]`}, - {`$x[$y:]`, 0, `a[:]`}, - {`x[y:z]`, 1, `x[y:z]`}, - {`x[y:z]`, 0, `_[y:z]`}, - {`x[y:z]`, 0, `x[_:z]`}, - {`x[y:z]`, 0, `x[y:_]`}, - {`x[y:z]`, 0, `x[y:]`}, - {`x[:y:z]`, 1, `x[:y:z]`}, - {`x[:y:z]`, 0, `_[:y:z]`}, - {`x[:y:z]`, 0, `x[:_:z]`}, - {`x[:y:z]`, 0, `x[:y:_]`}, - {`x[:y:z]`, 0, `x[0:y:z]`}, - {`x[:y:z]`, 0, `x[:y]`}, - {`x[5:y:z]`, 1, `x[5:y:z]`}, - {`x[5:y:z]`, 0, `_[5:y:z]`}, - {`x[5:y:z]`, 0, `x[_:y:z]`}, - {`x[5:y:z]`, 0, `x[5:_:z]`}, - {`x[5:y:z]`, 0, `x[5:y:_]`}, - {`x[5:y:z]`, 0, `x[0:y:z]`}, - {`x[5:y:z]`, 0, `x[5:y]`}, - {`x[$*_:]`, 1, `x[:]`}, - {`x[$*_:]`, 1, `x[1:]`}, - {`x[$*_:]`, 0, `x[1:2]`}, - {`x[:$*_]`, 1, `x[:]`}, - {`x[:$*_]`, 1, `x[:2]`}, - {`x[:$*_]`, 0, `x[1:2]`}, - {`x[$*_:$*_]`, 1, `x[:]`}, - {`x[$*_:$*_]`, 1, `x[1:]`}, - {`x[$*_:$*_]`, 1, `x[:2]`}, - {`x[$*_:$*_]`, 1, `x[1:2]`}, - {`x[$*_:$*_]`, 0, `x[1:2:2]`}, - {`x[$*_:$*_:$*_]`, 1, `x[:]`}, - {`x[$*_:$*_:$*_]`, 1, `x[1:]`}, - {`x[$*_:$*_:$*_]`, 1, `x[:2]`}, - {`x[$*_:$*_:$*_]`, 1, `x[1:2]`}, - {`x[$*_:$*_:$*_]`, 1, `x[1:2:2]`}, - {`x[$*y:$*y]`, 1, `x[:]`}, - {`x[$*y:$*y]`, 1, `x[1:1]`}, - {`x[$*y:$*y]`, 0, `x[1:0]`}, - - // Composite literals. - {`[]int{1, $x, $x}`, 1, `[]int{1, 2, 2}`}, - {`[]int{1, $x, $x}`, 0, `[]byte{1, 2, 2}`}, - {`[]int{1, $x, $x}`, 0, `[2]int{1, 2, 2}`}, - {`[]int{1, $x, $x}`, 0, `[]int{1, 2}`}, - {`[]string{$*_}`, 1, `[]string{"x", "y"}`}, - {`[][]int{{$x, $y}}`, 1, `[][]int{{f(), 1}}`}, - {`[][]int{{$x, $y}}`, 0, `[][]int{[]int{f(), 1}}`}, - {`[][]int{[]int{$x, $y}}`, 1, `[][]int{[]int{f(), 1}}`}, - {`[][]int{[]int{$x, $y}}`, 0, `[][]int{{f(), 1}}`}, - {`[]float64{$x}`, 1, `[]float64{3}`}, - {`[2]bool{$x, 0}`, 0, `[2]bool{3, 1}`}, - {`someStruct{fld: $x}`, 0, `someStruct{fld: a, fld2: b}`}, - {`map[int]int{1: $x}`, 1, `map[int]int{1: a}`}, - {`map[int]int{1: $x}`, 0, `map[int]byte{1: a}`}, - - // Type assert. - {`$x.([]string)`, 1, `a.([]string)`}, - {`$x.(string)`, 0, `a.(int)`}, - {`$x.($_)`, 1, `a.(b)`}, - {`$x.($x)`, 1, `int.(int)`}, - {`$x.($x)`, 0, `int.([]string)`}, - {`x.(string)`, 0, `y.(string)`}, - - // Type expr. - {`[8]$x`, 1, `[8]int{4: 1}`}, - {`struct{}`, 1, `type _ struct{}`}, - {`struct{}`, 1, `struct{}{}`}, - {`struct{}`, 0, `type _ struct{x int}`}, - {`struct{field $t}`, 1, `struct{field int}{}`}, - {`struct{field $t}`, 1, `struct{field int}{}`}, - {`struct{field $t}`, 0, `struct{other int}{}`}, - {`struct{field $t}`, 0, `(struct{f1, f2 int}{})`}, - {`struct{$*_}`, 1, `struct{}{}`}, - {`struct{$*_}`, 1, `struct{x int}{}`}, - {`struct{$*_}`, 1, `struct{x, y int}{}`}, - {`struct{$*_}`, 1, `struct{x int; y float64}{}`}, - {`struct{$*_}`, 0, `1`}, - {`struct{$_ $x; $_ $x}`, 1, `struct{x int; y int}{}`}, - {`struct{$_ $x; $_ $x}`, 0, `struct{x int; y string}{}`}, - {`struct{$*_; $_ $x; $_ $x; $*_}`, 1, `struct{x int; y int}{}`}, - {`struct{$*_; $_ $x; $_ $x; $*_}`, 1, `struct{x int; y int; z string}{}`}, - {`struct{$*_; $_ $x; $_ $x; $*_}`, 0, `struct{x string; y int; z string}{}`}, - {`struct{$x; $x}`, 1, `struct{x int; x int}{}`}, - {`struct{$x; $x}`, 0, `struct{x int; y int}{}`}, - {`struct{$x; $x}`, 0, `struct{x int; x string}{}`}, - {`struct{$x; $x}`, 0, `struct{x int}{}`}, - {`struct{$_}`, 1, `struct{io.Reader}{}`}, - {`struct{$_}`, 0, `struct{}{}`}, - {`struct{$_}`, 0, `struct{x int}{}`}, - {`struct{$_ $_}`, 1, `struct{x int}{}`}, - {`struct{$_, $_ $_}`, 1, `struct{x, y int}{}`}, - {`struct{$_, $_ $_}`, 0, `struct{x int}{}`}, - {`struct{$_, $_ $_}`, 0, `struct{x int; y int}{}`}, - {`var x struct{$x}; var y $x`, 1, `{ var x struct{io.Reader}; var y io.Reader }`}, - {`var x struct{$_ $x}; var y $x`, 1, `{ var x struct{r io.Reader}; var y io.Reader }`}, - {`var x struct{$x}; var y $x`, 0, `{ var x struct{io.Writer}; var y io.Reader }`}, - {`var x struct{$_ $x}; var y $x`, 0, `{ var x struct{r io.Writer}; var y io.Reader }`}, - {`var x struct{$_ $x}; var y $x`, 0, `{ var x struct{io.Reader}; var y io.Reader }`}, - {`interface{$x() int}`, 1, `(interface{i() int})(nil)`}, - {`interface{}`, 1, `interface{}(nil)`}, - {`interface{}`, 1, `interface{}(nil)`}, - {`interface{}`, 0, `interface{io.Reader}(nil)`}, - {`interface{}`, 0, `interface{Int() int}(nil)`}, - {`interface{Int() int}`, 1, `interface{Int() int}(nil)`}, - {`interface{Int() int}`, 0, `interface{String() int}(nil)`}, - {`interface{Int() int}`, 0, `interface{Int() string}(nil)`}, - {`interface{Int() int}`, 0, `interface{}(nil)`}, - {`interface{$_($x) $x}`, 1, `interface{Foo(int) int}(nil)`}, - {`interface{$_($x) $x}`, 0, `interface{Foo() int}(nil)`}, - {`interface{$_($x) $x}`, 0, `interface{Foo(int)}(nil)`}, - {`interface{$_($x) $x}`, 0, `interface{Foo(string) int}(nil)`}, - {`interface{$*_; String() string; $*_}`, 1, `interface{String() string}(nil)`}, - {`interface{$*_; String() string; $*_}`, 1, `interface{Int() int; String() string}(nil)`}, - {`interface{$*_; String() string; $*_}`, 1, `interface{String() string; Int() int}(nil)`}, - {`interface{$*_; String() string; $*_}`, 1, `interface{Float() float64; String() string; Int() int}(nil)`}, - {`chan<- int`, 1, `make(chan<- int)`}, - {`chan<- int`, 0, `make(chan <-string)`}, - {`chan<- int`, 0, `make(chan int)`}, - {`chan<- int`, 0, `make(<-chan int)`}, - {`chan $x`, 1, `new(chan bool)`}, - {`chan $x`, 0, `(chan<- bool)(nil)`}, - - // Key-value expr. - {`"a": 1`, 1, `map[string]int{"a": 1}`}, - {`"a": 1`, 0, `map[string]int{"a": 0}`}, - {`"a": 1`, 0, `map[string]int{"b": 1}`}, - {`"a": 1`, 0, `map[string]int{}`}, - {`$x: 1`, 1, `map[string]int{"x": 1}`}, - {`$x: 1`, 1, `map[string]int{"y": 1}`}, - {`$x: 1`, 0, `map[string]int{"z": 2}`}, - {`"a": $x`, 1, `map[string]int{"a": 1}`}, - {`"a": $x`, 1, `map[string]int{"a": 2}`}, - {`"a": $x`, 0, `map[string]int{"b": 3}`}, - - // Func lit. - {`func () {}`, 1, `func () {}`}, - {`func () {}`, 0, `func () int {}`}, - {`func () {}`, 0, `func (int) {}`}, - {`func () {}`, 0, `func (x int) {}`}, - {`func () {}`, 0, `func (int, int) {}`}, - {`func (x int) {}`, 1, `func (x int) {}`}, - {`func (x int) {}`, 0, `func (y int) {}`}, - {`func (x int) {}`, 0, `func (x string) {}`}, - {`func (int) {}`, 1, `func (int) {}`}, - {`func (int) {}`, 0, `func (string) {}`}, - {`func (int) {}`, 0, `func () {}`}, - {`func (int) {}`, 0, `func (int, int) {}`}, - {`func (int) {}`, 0, `func (int) int {}`}, - {`func (int, int) {}`, 1, `func (int, int) {}`}, - {`func (int, int) {}`, 0, `func (int) {}`}, - {`func (int, int) {}`, 0, `func (x int, y int) {}`}, - {`func (int, int) {}`, 0, `func (string, int) {}`}, - {`func (int, int) {}`, 0, `func (int, string) {}`}, - {`func (int, int) {}`, 0, `func (int, int) int {}`}, - {`func (x, y int) int {}`, 1, `func (x, y int) int {}`}, - {`func (x, y int) int {}`, 0, `func (x int, y int) int {}`}, - {`func (x, y int) int {}`, 0, `func (x, y string) int {}`}, - {`func (x, y int) int {}`, 0, `func (x, y int) string {}`}, - {`func (x, y int) int {}`, 0, `func (x, y int) (int, int) {}`}, - {`func (x, y int) int {}`, 0, `func (y, x int) int {}`}, - {`func () (int, int) {}`, 1, `func () (int, int) {}`}, - {`func () (int, int) {}`, 0, `func () int {}`}, - {`func () (int, int) {}`, 0, `func () (string, int) {}`}, - {`func () (int, int) {}`, 0, `func () (x int, y int) {}`}, - {`func () int { return 1 }`, 1, `func () int { return 1 }`}, - {`func () int { return 1 }`, 0, `func () int { return 0 }`}, - {`func ($t, $t) {}`, 1, `func (int, int) {}`}, - {`func ($t, $t) {}`, 0, `func (string, int) {}`}, - {`func ($t, $t) {}`, 0, `func (int, string) {}`}, - {`func($s string) { print($s) }`, 1, `func(a string) { print(a) }`}, - {`func(x ...int) {}`, 1, `func(x ...int) {}`}, - {`func(x ...int) {}`, 0, `func(x int) {}`}, - {`func(x ...int) {}`, 0, `func(y ...int) {}`}, - {`func(x ...int) {}`, 0, `func(x ...string) {}`}, - {`func($x ...$t) {}`, 1, `func(a ...int) {}`}, - - // Func lit - non-strict mode. - // TODO: reject these in strict mode. - {`func () (int) {}`, 1, `func () int {}`}, - {`func () int {}`, 1, `func () (int) {}`}, - - // Assign stmt. - {`$x = $y`, 1, `a = b`}, - {`x := y`, 0, `x = y`}, - {`$x := $y`, 0, `a, b := c()`}, - {`$x := $y`, 0, `a, b = c()`}, - {`$x := $y`, 0, `a, b := c, d`}, - {`$*x = $*x`, 1, `x, y = x, y`}, - {`$*x = $*x`, 0, `x, y = 0, 0`}, - {`$*_ = $*_`, 1, `x = 1`}, - {`$*_ = $*_`, 1, `x, y = 1, 2`}, - - // Block stmt. - {`{ $x }`, 1, `{ a() }`}, - {`{ $x }`, 0, `{ a(); b() }`}, - {`{}`, 1, `package p; func f() {}`}, - {`{ $*_ }`, 1, `{ x; y }`}, - {`{ x; y }`, 1, `{ x; y }`}, - {`{ x; y; z }`, 1, `{ x; y; z }`}, - {`{ x; y }`, 0, `{ y; x }`}, - {`{ x; y }`, 0, `{ x }`}, - {`{ x; f(); y; g() }`, 1, `{ x; f(); y; g() }`}, - {`{ x; $*_; g() }`, 1, `{ x; f(); y; g() }`}, - {`{ $*_; g() }`, 1, `{ x; f(); y; g() }`}, - {`{ x; $*_ }`, 1, `{ x; f(); y; g() }`}, - {`{ x; $*_ }`, 1, `{ x; y }`}, - {`{ x; $*_ }`, 0, `{ y; x }`}, - {`{ $*_; y }`, 1, `{ x; y }`}, - {`{ $*_; y }`, 0, `{ y; x }`}, - {`{ $*_; f(); $*_ }`, 1, `{ f() }`}, - {`{ $*_; f(); $*_ }`, 1, `{ g(); f() }`}, - {`{ $*_; x; $*_ }`, 1, `{ y; x; y }`}, - {`{ $*_; f(); $*_ }`, 1, `{ g(); g(); f() }`}, - {`{ $*_; f(); $*_ }`, 0, `{ g(); g() }`}, - {`{ $*_; f(); $*_ }`, 0, `{}`}, - {`{ $*_; return nil }`, 1, `{ return nil }`}, - {`{ $*_; return nil }`, 1, `{ a(); b(); return nil }`}, - - // Labeled stmt. - {`foo: if x {}`, 1, `foo: if x {}`}, - {`foo: if x {}`, 0, `foo: if y {}`}, - {`foo: if x {}`, 0, `bar: if y {}`}, - {`$label: if f() {}`, 1, `foo: if f() {}`}, - {`$label: if f() {}`, 1, `bar: if f() {}`}, - {`$l: return 1; $l: return 2`, 1, `{ x: return 1; x: return 2 }`}, - {`$l: return 1; $l: return 2`, 0, `{ x: return 1; y: return 2 }`}, - - // Send stmt. - {`x <- 1`, 1, `x <- 1`}, - {`x <- $v`, 0, `y <- 0`}, - {`x <- 1`, 0, `x <- 2`}, - - // Go stmt. - {`go f(1)`, 1, `go f(1)`}, - {`go f(1)`, 0, `go g(1)`}, - {`go func() { $x }()`, 1, `go func() { a() }()`}, - {`go func() { $x }()`, 0, `go a()`}, - - // Defer stmt. - {`defer f(1)`, 1, `defer f(1)`}, - {`defer f(1)`, 0, `defer g(1)`}, - {`defer func() { $x }()`, 1, `defer func() { a() }()`}, - {`defer func() { $x }()`, 0, `defer a()`}, - - // If stmt. - {`if $x != nil { $y }`, 1, `if p != nil { p.foo() }`}, - {`if $x { $y }`, 0, `if a { b() } else { c() }`}, - {`if $x != nil { $y }`, 1, `if a != nil { return a }`}, - {`if $_; cond {}`, 0, `if cond {}`}, - {`if $_; cond {}`, 1, `if init; cond {}`}, - {`if $x; cond {}`, 0, `if cond {}`}, - {`if $x; cond {}`, 1, `if init; cond {}`}, - {`if $x {} else if $x {}`, 1, `if cond {} else if cond {}`}, - {`if $x {} else if $x {}`, 0, `if cond {} else if cond2 {}`}, - {`if $x {} else if $x {}`, 0, `if cond {} else {}`}, - {`if $x {} else if $x {}`, 0, `if cond { f() } else {}`}, - {`if $x {} else if $x {}`, 0, `if cond {} else { f() }`}, - {`if $x {} else if $x {}`, 0, `if cond {} else if cond { f() }`}, - { - `if len($xs) != 0 { for _, $x = range $xs { $*_ } }`, - 1, - `if len(xs) != 0 { for _, v = range xs { println(v) } }`, - }, - { - `if len($xs) != 0 { for _, $x := range $xs { $*_ } }`, - 0, - `if len(xs) != 0 { for _, v = range xs { println(v) } }`, - }, - - // If stmt - optional matching. - {`if $*_; cond {}`, 1, `if cond {}`}, - {`if $*_; cond {}`, 1, `if init; cond {}`}, - {`if $*x; cond {}`, 1, `if cond {}`}, - {`if $*x; cond {}`, 1, `if init; cond {}`}, - {`if $*_ {}`, 1, `if cond {}`}, - {`if $*_ {}`, 1, `if init; cond {}`}, - {`if $*x {}; if $*x {}`, 1, `for cond() { if a(); b {}; if a(); b {} }`}, - {`if $*x {}; if $*x {}`, 1, `{ if a {}; if a {} }`}, - {`if $*x {}; if $*x {}`, 0, `{ if a {}; if b {} }`}, - {`if $*x {}; if $*x {}`, 0, `for cond() { if a(); b {}; if b {} }`}, - {`if $*x {} else if $*x {}`, 1, `{ if a {} else if a {} }`}, - {`if $*x {} else if $*x {}`, 0, `{ if a {} else if b {} }`}, - {`if $*_ {} else {}`, 0, `if a(); b {}`}, - {`if $*_; $_ {} else {}`, 1, `if a() {} else {}`}, - {`if $*_; $_ {} else {}`, 1, `if a(); b {} else {}`}, - {`if $*_ {} else {}`, 1, `if a(); b {} else {}`}, - {`if $*_ {} else {}`, 1, `if a() {} else {}`}, - {`if a(); $*_ {}`, 0, `if b {}`}, - {`if $_ { $*_ }`, 1, `if cond {}`}, - {`if $_ { $*_ }`, 1, `if cond { f() }`}, - - // Switch stmt. - {`switch {}`, 1, `switch {}`}, - {`switch {}`, 0, `switch tag {}`}, - {`switch tag {}`, 1, `switch tag {}`}, - {`switch tag {}`, 0, `switch {}`}, - {`switch tag {}`, 0, `switch init; tag {}`}, - {`switch tag {}`, 0, `switch tag2 {}`}, - {`switch init; {}`, 1, `switch init; {}`}, - {`switch init; {}`, 0, `switch init2; {}`}, - {`switch init; {}`, 0, `switch init; tag {}`}, - {`switch init; {}`, 0, `switch {}`}, - {`switch init; tag {}`, 1, `switch init; tag {}`}, - {`switch init; tag {}`, 0, `switch init2; tag {}`}, - {`switch init; tag {}`, 0, `switch init; tag2 {}`}, - {`switch init; tag {}`, 0, `switch {}`}, - {`switch init; tag {}`, 0, `switch ; tag {}`}, - {`switch init; tag {}`, 0, `switch init; {}`}, - {`switch $_ {}`, 1, `switch x {}`}, - {`switch $_ {}`, 0, `switch x; y {}`}, - {`switch $_; $_ {}`, 0, `switch x {}`}, - {`switch $_; $_ {}`, 1, `switch x; y {}`}, - {`switch { $*_; case x: y() }`, 1, `switch { case x: y() }`}, - {`switch { $*_; case x: y() }`, 1, `switch { case v: g(); case x: y() }`}, - {`switch { $*_; case $*_: $*a }`, 1, `switch { case x: y() }`}, - {`switch x {case 4: x}`, 1, `switch x {case 4: x}`}, - {`switch x {case 4: x}`, 0, `switch y {case 4: x}`}, - {`switch x {case 4: x}`, 0, `switch x {case 5: x}`}, - {`switch {$_}`, 1, `switch {case 5: x}`}, - {`switch x {$_}`, 1, `switch x {case 5: x}`}, - {`switch x {$*_}`, 1, `switch x {case 5: x}`}, - {`switch x {$*_}`, 1, `switch x {}`}, - {`switch x {$*_}`, 1, `switch x {case 1: a; case 2: b}`}, - {`switch {$a; $a}`, 1, `switch {case true: a; case true: a}`}, - {`switch {$a; $a}`, 0, `switch {case true: a; case true: b}`}, - {`switch x {default: f()}`, 1, `switch x {default: f()}`}, - {`switch x {default: f()}`, 0, `switch x {default: g()}`}, - {`switch x {default: f()}`, 0, `switch x {case 10: f()}`}, - {`switch x := y.(z); x {}`, 1, `switch x := y.(z); x {}`}, - {`switch x := y.(z); x {}`, 0, `switch y := y.(z); x {}`}, - {`switch x := y.(z); x {}`, 0, `switch x {}`}, - {`switch x {case x, y: f(x, y)}`, 1, `switch x {case x, y: f(x, y)}`}, - {`switch x {case x, y: f(x, y)}`, 0, `switch x {case x: f(x, y)}`}, - {`switch x {case x, y: f(x, y)}`, 0, `switch x {case x, _: f(x, y)}`}, - {`switch x {case x, y: f(x, y)}`, 0, `switch x {case x, y: f(x, _)}`}, - - // Switch stmt - optional matching. - {`switch $*x {}`, 1, `switch a {}`}, - {`switch $*x {}`, 1, `switch {}`}, - {`switch $*_; b {}`, 1, `switch b := f(); b {}`}, - {`switch $*_; b {}`, 0, `switch b := f(); c {}`}, - //{`switch $*x {}`, 1, `switch a(); b {}`}, - //{`switch $*x {}; switch $*x {}`, 1, `{ switch a(); b {}; switch a(); b {} }`}, - {`switch $*x {}; switch $*x {}`, 0, `{ switch a(); b {}; switch b {} }`}, - {`switch a(); $*_ {}`, 0, `for b {}`}, - - // Type switch stmt. - {`switch x := $x.(type) {}`, 1, `switch x := y.(type) {}`}, - {`switch x := $x.(type) {}`, 1, `switch x := xs[0].(type) {}`}, - {`switch $x := $x.(type) {}`, 1, `switch x := x.(type) {}`}, - {`switch $x := $x.(type) {}`, 0, `switch y := x.(type) {}`}, - {`switch $x.(type) {}`, 1, `switch v.(type) {}`}, - {`switch $*_; x.(type) {}`, 1, `switch x.(type) {}`}, - {`switch $*_; x.(type) {}`, 1, `switch init(); x.(type) {}`}, - {`switch $*_; x.(type) {}`, 0, `switch y.(type) {}`}, - - // Select stmt. - {`select {$*_}`, 1, `select {case <-x: a}`}, - {`select {$*_}`, 1, `select {}`}, - {`select {$a; $a}`, 1, `select {case <-x: a; case <-x: a}`}, - {`select {$a; $a}`, 0, `select {case <-x: a; case <-x: b}`}, - {`select {case x := <-y: f(x)}`, 1, `select {case x := <-y: f(x)}`}, - {`select {default: f()}`, 1, `select {default: f()}`}, - {`select {default: f()}`, 0, `select {default: g()}`}, - {`select {default: f()}`, 0, `select {}`}, - {`select {default: f()}`, 0, `select {case <-x: f()}`}, - - // For stmt. - {`for {}`, 1, `for {}`}, - {`for {}`, 0, `for cond {}`}, - {`for {}`, 0, `for ; ; post {}`}, - {`for {}`, 0, `for { f() }`}, - {`for ; ; post {}`, 1, `for ; ; post {}`}, - {`for ; ; post {}`, 0, `for ; ; _ {}`}, - {`for ; ; post {}`, 0, `for {}`}, - {`for ; ; post {}`, 0, `for init; ; {}`}, - {`for ; ; post {}`, 0, `for ; cond; post {}`}, - {`for ; ; post {}`, 0, `for init; cond; {}`}, - {`for ; cond; {}`, 1, `for ; cond; {}`}, - {`for ; cond; {}`, 0, `for ; _; {}`}, - {`for ; cond; {}`, 0, `for {}`}, - {`for ; cond; {}`, 0, `for init; cond; {}`}, - {`for ; cond; {}`, 0, `for ; cond; post {}`}, - {`for ; cond; post {}`, 1, `for ; cond; post {}`}, - {`for ; cond; post {}`, 0, `for ; _; post {}`}, - {`for ; cond; post {}`, 0, `for ; cond; _ {}`}, - {`for ; cond; post {}`, 0, `for {}`}, - {`for ; cond; post {}`, 0, `for ; ; post {}`}, - {`for ; cond; post {}`, 0, `for ; _; post {}`}, - {`for ; cond; post {}`, 0, `for init; cond; post {}`}, - {`for init; ; {}`, 1, `for init; ; {}`}, - {`for init; ; {}`, 0, `for _; ; {}`}, - {`for init; ; {}`, 0, `for {}`}, - {`for init; ; {}`, 0, `for init; cond; {}`}, - {`for init; ; {}`, 0, `for init; ; post {}`}, - {`for init; ; post {}`, 1, `for init; ; post {}`}, - {`for init; ; post {}`, 0, `for {}`}, - {`for init; ; post {}`, 0, `for init; ; _ {}`}, - {`for init; ; post {}`, 0, `for _; ; post {}`}, - {`for init; ; post {}`, 0, `for init; cond; post {}`}, - {`for init; cond; {}`, 1, `for init; cond; {}`}, - {`for init; cond; {}`, 0, `for init; cond; post {}`}, - {`for init; cond; post {}`, 1, `for init; cond; post {}`}, - {`for init; cond; post {}`, 0, `for init; ; post {}`}, - {`for init; cond; post {}`, 0, `for _; cond; post {}`}, - - // For stmt - optional matching. - {`for $*_; $*_; $*_ {}`, 1, `for {}`}, - {`for $*_; $*_; $*_ {}`, 1, `for ; init; {}`}, - {`for $*x; $*_; $*x {}`, 1, `for f(); cond; f() {}`}, - {`for $*x; $*_; $*x {}`, 1, `for ; cond; {}`}, - {`for $*x; $*_; $*x {}`, 0, `for f(); cond; g() {}`}, - {`for $*x; $*_; $*x {}`, 0, `for f(); cond; {}`}, - {`for $*x; $*_; $*x {}`, 0, `for ; cond; g() {}`}, - - // For stmt - unintentional matches (see https://github.com/golang/go/issues/44257). - {`for {}`, 1, `for ;; {}`}, - {`for cond {}`, 1, `for ; cond; {}`}, - {`for ;; {}`, 1, `for {}`}, - {`for ; cond; {}`, 1, `for cond {}`}, - - // Range stmt. - {`for range xs {}`, 1, `for range xs {}`}, - {`for range xs {}`, 0, `for range xs { f() }`}, - {`for range xs {}`, 0, `for range ys {}`}, - {`for range xs {}`, 0, `for i := range xs {}`}, - {`for range xs {}`, 0, `for i, x := range xs {}`}, - {`for i := range xs {}`, 1, `for i := range xs {}`}, - {`for i := range xs {}`, 0, `for i = range xs {}`}, - {`for i := range xs {}`, 0, `for i := range ys {}`}, - {`for i := range xs {}`, 0, `for j := range xs {}`}, - {`for i := range xs {}`, 0, `for range xs {}`}, - {`for i, x := range xs {}`, 1, `for i, x := range xs {}`}, - {`for i, x := range xs {}`, 0, `for i, x = range xs {}`}, - {`for i, x := range xs {}`, 0, `for j, x := range xs {}`}, - {`for i, x := range xs {}`, 0, `for i, y := range xs {}`}, - {`for i, x := range xs {}`, 0, `for i, x := range ys {}`}, - {`for i, x := range xs {}`, 0, `for range xs {}`}, - {`for $x := range $y { $z }`, 1, `for i := range l { c() }`}, - {`for $x := range $y { $z }`, 0, `for i = range l { c() }`}, - {`for $x = range $y { $z }`, 0, `for i := range l { c() }`}, - {`for range $y { $z }`, 0, `for _, e := range l { e() }`}, - - // Range stmt - optional matching. - {`for $*x; b; $*x {}`, 1, `for b {}`}, - {`for $*x; b; $*x {}`, 1, `for a(); b; a() {}`}, - {`for $*x; b; $*x {}`, 0, `for a(); b; c() {}`}, - // TODO: - // {`for $*_ := range $_ {}`, 1, `for i := range xs {}`}, - // {`for $*_ = range $_ {}`, 1, `for i = range xs {}`}, - // {`for $*_ := range $_ {}`, 1, `for i, x := range xs {}`}, - // {`for $*_ = range $_ {}`, 1, `for i, x = range xs {}`}, - // {`for $*_ := range $_ {}`, 0, `for i, x = range xs {}`}, - // {`for $*_ := range $_ {}`, 0, `for {}`}, - // {`for $*_ := range $_ {}`, 0, `for cond {}`}, - // TODO: - // {`for $*_ range $_ {}`, 1, `for range xs {}`}, - - // Any for loop. - // TODO: need to solve https://github.com/golang/go/issues/44257 first. - // {`for $*_ {}`, 1, `for {}`}, - // {`for $*_ {}`, 1, `for i := 0; i < 10; i++ {}`}, - // {`for $*_ {}`, 1, `for range xs {}`}, - // {`for $*x {}; for $*x {}`, 1, `{ for {}; for {} }`}, - // {`for $*x {}; for $*x {}`, 1, `{ for {}; for cond {} }`}, - // {`for $*x {}; for $*x {}`, 1, `{ for x {}; for x {} }`}, - // {`for $*x {}; for $*x {}`, 0, `{ for x {}; for y {} }`}, - // {`for $*x {}; for $*x {}`, 1, `{ for range xs {}; for range xs {} }`}, - // {`for $*x {}; for $*x {}`, 0, `{ for range xs {}; for range ys {} }`}, - // {`for $*x {}; for $*x {}`, 1, `{ for a(); b(); {}; for a(); b(); {} }`}, - // {`for $*x {}; for $*x {}`, 0, `{ for a(); b(); {}; for a(); b(); c() {} }`}, - - // Mixing expr and stmt lists. - {`$x, $y`, 0, `{ 1; 2 }`}, - {`$x; $y`, 0, `f(1, 2)`}, - - // Stmt list (+ partial matches). - {`$*x; b; $*y`, 1, `{ a; b; c }`}, - {`$*x; b; $*x`, 0, `{ a; b; c }`}, - {`x; y`, 1, `{ x; y; z }`}, - {`x; y`, 1, `{ z; x; y }`}, - {`f(1); g(2)`, 1, `{ z; f(1); g(2); z }`}, - {`x; y`, 0, `{ x; z; y }`}, - {`x; y`, 0, `{ y; x; z }`}, - {`x; y`, 0, `{ x }`}, - {`f(g(1), 2, 3); $*_; $x; $x`, 1, `{ f(g(1), 2, 3); g(); g() }`}, - {`f(g(1), 2, 3); $*_; $x; $x`, 1, `{ f(g(1), 2, 3); g(); g(); g() }`}, - {`f(g(1), 2, 3); $*_; $x; $x`, 1, `{ f(g(1), 2, 3); f(); g(); g() }`}, - {`f(g(1), 2, 3); $*_; $x; $x`, 1, `{ f(g(1), 2, 3); f(); g(); g(); f() }`}, - {`f(g(1), 2, 3); $*_; $x; $x`, 0, `{ f(g(1), 2, 3); f(); g(); f() }`}, - {`x.a(); x.b()`, 2, `if cond { x.a(); x.b(); f(); x.a(); x.b() }`}, - {`x; x`, 1, `{ x; x; x }`}, - {`$x(); $y()`, 1, `{ a(); b() }`}, - {`$x(); $y()`, 0, `{ a() }`}, - {`$x++; $x--`, 1, `{ n; a++; b++; b-- }`}, - {`$*_; b; $*_`, 1, `{a; b; c; d}`}, - {`c($*x); c($*x)`, 1, `{ c(); c() }`}, - {`c($*x); c()`, 1, `{ c(); c() }`}, - {`c($*x); c($*x)`, 0, `if cond { c(x); c(y) }`}, - {`c($*x); c($*x)`, 0, `if cond { c(x, y); c(z) }`}, - {`c($*x); c($*x)`, 1, `if cond { c(x, y); c(x, y) }`}, - {`c($*x, y); c($*x, y)`, 1, `if cond { c(x, y); c(x, y) }`}, - {`c($*x, $*y); c($*x, $*y)`, 1, `{ c(x, y); c(x, y) }`}, - {`$x := $_; $x = $_`, 1, `{ a := n; b := n; b = m }`}, - {`$x := $_; $*_; $x = $_`, 1, `{ a := n; b := n; b = m }`}, - {`var x int; if true { f() }`, 1, `{ var x int; if true { f() } }`}, - {`var $v $_; if true { $_ }`, 1, `{ var x int; if true { x = 10 } }`}, - {`var $v $_; if $*_ { $_ }`, 1, `{ var x int; if true { x = 10 } }`}, - {`var $v $_; if $cond { $_ }`, 1, `{ var x int; if true { x = 10 } }`}, - {`var $v $_; if $cond { $v = $x }`, 1, `{ var x int; if true { x = 10 } }`}, - {`var $v $_; if $cond { $v = $x } else { $v = $y }`, 1, `{ var x int; if true { x = 10 } else { x = 20 } }`}, - {`f(); if $ok { $*_; }`, 1, `{ f(); if ok {} }`}, - {`$_, $ok := $m.Load($k); if $ok {}`, 1, `{ v, ok := m.Load(k); if ok {} }`}, - {`$_, $ok := $m.Load($k); if $ok { $*_ }`, 1, `{ v, ok := m.Load(k); if ok {} }`}, - {`$_, $ok := $m.Load($k); if $ok { $*_ }`, 1, `{ v, ok := m.Load(k); if ok { f() } }`}, - {`$_, $ok := $m.Load($k); if $ok { $*_ }`, 0, `{ v, ok1 := m.Load(k); if ok2 { f() } }`}, - {`$_, $ok := $m.Load($k); if $ok { $*_ }`, 0, `{ v, ok := m.Load(k) }`}, - - // Expr list (+ partial matches). - {`b, c`, 1, `[]int{a, b, c, d}`}, - {`b, c`, 1, `foo(a, b, c, d)`}, - {`x, x`, 1, `f(x, x)`}, - {`x, x`, 1, `f(_, x, x)`}, - {`x, x`, 1, `f(x, x, _)`}, - {`x, x`, 1, `f(_, x, x, _)`}, - {`$x, $y`, 1, `foo(1, 2)`}, - {`2, 3`, 1, `foo(1, 2, 3)`}, - {`$x, $x, $x`, 1, `foo(1, 1, 1)`}, - {`$x, $x, $x`, 1, `foo(2, 1, 1, 1)`}, - {`$x, $x, $x`, 1, `foo(1, 1, 1, 2)`}, - {`$x, $x, $x`, 1, `foo(2, 1, 1, 1, 2)`}, - {`$x, $x, $x`, 1, `[]int{1, 1, 1, 2}`}, - {`$x, $x, $x`, 1, `[]int{2, 1, 1, 1}`}, - {`$x, $x, $x`, 1, `[]int{2, 1, 1, 1, 2}`}, - {`$x, $y`, 0, `1`}, - {`$x`, 5, `[]string{a, b}`}, - {`$x, $x`, 1, `return 1, 1`}, - {`$x, $x`, 1, `return 0, 1, 0, 1, 1`}, - {`$x, $x`, 1, `return 0, 1, 1, 0`}, - - // Inc/dec stmt. - {`x++`, 1, `x++`}, - {`x++`, 0, `y++`}, - {`$x++`, 1, `a[b]++`}, - {`$x--`, 0, `a++`}, - - // Return stmt. - {`return`, 1, `return`}, - {`return`, 0, `return 1`}, - {`return nil, $x`, 1, `{ return nil, err }`}, - {`return nil, $x`, 0, `{ return nil, 0, err }`}, - {`return $*_, err, $*_`, 1, `return err`}, - {`return $*_, err, $*_`, 1, `return 1, err`}, - {`return $*_, err, $*_`, 1, `return 1, err, 2`}, - {`return $*_, err, $*_`, 1, `return 1, 2, err`}, - {`return $*_, err, $*_`, 0, `return 1, 2`}, - {`return $*_, err, $*_`, 0, `return`}, - - // Branch stmt. - {`break foo`, 1, `break foo`}, - {`break foo`, 0, `break`}, - {`break foo`, 0, `break bar`}, - {`break foo`, 0, `continue foo`}, - {`break foo`, 0, `break`}, - {`break`, 1, `break`}, - {`break`, 0, `break foo`}, - {`goto foo`, 1, `goto foo`}, - {`goto foo`, 0, `goto bar`}, - {`fallthrough`, 1, `fallthrough`}, - {`fallthrough`, 0, `break`}, - {`continue`, 1, `continue`}, - {`continue`, 0, `continue foo`}, - {`continue`, 0, `break`}, - {`break $x`, 1, `break foo`}, - {`break $x`, 0, `break`}, - {`break $x; break $x`, 1, `{ break foo; break foo }`}, - {`break $x; break $x`, 0, `{ break foo; break bar }`}, - - // Ellipsis. - {`append(xs, ys...)`, 1, `append(xs, ys...)`}, - {`append(xs, ys...)`, 0, `append(xs, ys)`}, - {`append($x, $y...)`, 1, `append(a, bs...)`}, - {`append($b[$i], append([]$_{$_}, $b[$i:]...)...)`, 1, `append(b[i], append([]int{x}, b[i:]...)...)`}, - {`append($b[$i], append([]$_{$_}, $b[$i:]...)...)`, 1, `append(b2[j], append([]int{10}, b2[j:]...)...)`}, - {`append($b[$i], append([]$_{$_}, $b[$i:]...)...)`, 0, `append(b1[i], append([]int{x}, b2[i:]...)...)`}, - {`append($b[$i], append([]$_{$_}, $b[$i:]...)...)`, 0, `append(b[i1], append([]int{x}, b[i2:]...)...)`}, - {`append($b[$i], append([]$_{$_}, $b[$i:]...)...)`, 0, `append(b2[j], append([]int{10}, b2[j:]...))`}, - {`append($b[$i], append([]$_{$_}, $b[$i:]...)...)`, 0, `append(b2[j], append([]int{10}, b2[j:])...)`}, - {`append($b[$i], append([]$_{$_}, $b[$i:]...)...)`, 0, `append(b2[j], append([]int{10}, b2[j:]))`}, - {`append($b[:$i], append($_, $b[$i:]...)...)`, 1, `append(b[:i], append(el, b[i:]...)...)`}, - {`append($b[:$i], append($_, $b[$i:]...)...)`, 0, `append(b[:i], append(el, b[i:]...))`}, - {`append($b[:$i], append($_, $b[$i:]...)...)`, 0, `append(b[:i], append(el, b[i:])...)`}, - {`append($b[:$i], append($_, $b[$i:]...)...)`, 0, `append(b[:i], append(el, b[i:]))`}, - {`append($b[:$i], append($_, $b[$i:]...)...)`, 0, `append(b[:i1], append(el, b[i:]...)...)`}, - {`append($b[:$i], append($_, $b[$i:]...)...)`, 0, `append(b[:i], append(el, b[i1:]...)...)`}, - {`append($b[:$i], append($_, $b[$i:]...)...)`, 0, `append(b1[:i], append(el, b[i1:]...)...)`}, - {`append($b[:$i], append($_, $b[$i:]...)...)`, 0, `append(b[:i], append(el, b2[i1:]...)...)`}, - {`append($b[:$i], append($_, $b[$i:]...)...)`, 0, `append(b[:i], append(el, b2[i1:])...)`}, - {`append($b[:$i], append($_, $b[$i:]...)...)`, 0, `append(b[:i], append(el, b2[i1:]...))`}, - {`foo($x...)`, 0, `foo(a)`}, - {`foo($x...)`, 0, `foo(a, b)`}, - {`foo($x)`, 0, `foo(x...)`}, - {`[...]int{}`, 1, `[...]int{}`}, - {`[...]int{}`, 0, `[1]int{}`}, - {`[1]int{}`, 0, `[...]int{}`}, - {`[$_]int{}`, 1, `[...]int{}`}, - - // Func decl. - {`func f() {}`, 1, `package p; func f() {}`}, - {`func f() {}`, 0, `package p; func (object) f() {}`}, - {`func (object) f() {}`, 1, `package p; func (object) f() {}`}, - {`func (object) f() {}`, 0, `package p; func f() {}`}, - {`func (object) f() {}`, 0, `package p; func (foo) f() {}`}, - {`func (object) f() {}`, 0, `package p; func (o object) f() {}`}, - {`func f() int`, 1, `package p; func f() int`}, - {`func f() int`, 0, `package p; func f() int {}`}, - {`func (object) f() int`, 1, `package p; func (object) f() int`}, - {`func (object) f() int`, 0, `package p; func (object) f() int {}`}, - { - `func $_($x $y) $y { return $x }`, - 1, - `package p; func a(i int) int { return i }`, - }, - {`func $x(i int)`, 1, `package p; func a(i int)`}, - {`func $x(i int) {}`, 0, `package p; func b(i int)`}, - {`func $_() $*_ { $*_ }`, 1, `package p; func f() { return 0 }`}, - {`func $_() $*_ { $*_ }`, 1, `package p; func f() int { return 0 }`}, - {`func $_() $*_ { $*_ }`, 1, `package p; func f() (int, string) { return 0, "" }`}, - {`func $_() $*_ { $*_ }`, 1, `package p; func f() (a int, b string) { return }`}, - {`func $_() $*_ { $*_ }`, 1, `package p; func f() (int, error) { return 3, nil }`}, - {`func $_($*_) $x { return $x(0) }`, 1, `package p; func f() int { return int(0) }`}, - {`func $_($*_) $x { return $x(0) }`, 0, `package p; func f() int { return uint(0) }`}, - {`func $_($*_) $_ { $*_ }`, 0, `package p; func f() {}`}, - {`func $_($*_) $_ { $*_ }`, 0, `package p; func f() (int, string) { return }`}, - {`func $_($*_) $_ { $*_ }`, 0, `package p; func f() (x int) { return 0 }`}, - {`func $_($*_) ($_ $_) { $*_ }`, 1, `package p; func f() (x int) { return 0 }`}, - {`func $_($*_) $_ { $*_ }`, 1, `package p; func f() int { return 0 }`}, - {`func ($x $y) $f($*_) { $*_ }`, 1, `package p; func (t *MyType) methodName() {}`}, - {`func ($x $y) $f($*_) $*_ { $*_ }`, 1, `package p; func (t *MyType) methodName() (int, int) { return 0, 0 }`}, - {`func $_($_ $_) {}`, 1, `package p; func f(x int) {}`}, - {`func $_($_ $_, $_ $_) {}`, 1, `package p; func f(x int, y int) {}`}, - {`func $_($_, $_ $_) {}`, 1, `package p; func f(x, y int) {}`}, - {`func $_($_) {}`, 0, `package p; func f(x int) {}`}, - {`func $_($_) {}`, 0, `package p; func f(x int, y int) {}`}, - {`func $_($_) {}`, 0, `package p; func f(x, y int) {}`}, - {`func $_($_) {}`, 0, `package p; func f() {}`}, - - // Gen decl. - {`const $_ $*_ = iota`, 1, `const foo = iota`}, - {`const $_ $*_ = iota`, 1, `const foo int = iota`}, - {`const $_ $*_ = iota`, 1, `const (foo = iota)`}, - {`const $_ $*_ = iota`, 1, `const (foo int = iota)`}, - {`const $_ $*_ = iota`, 0, `const foo int = 0`}, - {`const $_ $*_ = iota`, 0, `var foo = iota`}, - {`const $_ $_ = iota`, 1, `const foo int = iota`}, - {`const $_ $_ = iota`, 0, `const foo = iota`}, - {`const $x = $y`, 1, `const a = b`}, - {`const $x = $y`, 1, `const (a = b)`}, - {`const $x = $y`, 0, "const (a = b\nc = d)"}, - {`const (x = 1; y = 2)`, 1, `const (x = 1; y = 2)`}, - {`const (x = 1; y = 2)`, 0, `const (x = 1; y = 1)`}, - {`const (x = 1; y = 2)`, 0, `const (y = 1; x = 1)`}, - {`const (x = iota; y)`, 1, `const (x = iota; y)`}, - {`const ($_ $_ = iota; $*_)`, 1, `{ const (x int = iota) }`}, - {`const ($_ $_ = iota; $*_)`, 1, `{ const (x int = iota; y) }`}, - {`const ($_ $_ = iota; $*_)`, 1, `{ const (x int = iota; y; z) }`}, - {`const ($_ $_ = iota; $_)`, 1, `{ const (x int = iota; y) }`}, - {`const ($_ $_ = iota; $_)`, 0, `{ const (x int = iota) }`}, - {`const ($_ $_ = iota; $_)`, 0, `{ const (x int = iota; y; z) }`}, - {`var x $_`, 1, `var x int`}, - {`var x $_`, 0, `var y int`}, - {`var $x int`, 1, `var a int`}, - {`var $x int`, 0, `var a int = 3`}, - {`var ()`, 1, `var()`}, - {`var ()`, 0, `var(x int)`}, - {`type x int`, 1, `type x int`}, - {`type x int`, 0, `type _ int`}, - {`type x int`, 0, `type x _`}, - {`type x int`, 0, `type x = int`}, - {`type x = int`, 1, `type x = int`}, - {`type x = int`, 0, `type _ = int`}, - {`type x = int`, 0, `type x = _`}, - {`type x = int`, 0, `type x int`}, - {`type $x int`, 1, `type foo int`}, - {`type x $t`, 1, `type x string`}, - {`type ()`, 1, `type ()`}, - {`type ()`, 0, `type (x int)`}, - {`type ()`, 0, `type x int`}, - {`type $_ struct{$*_}`, 1, `type foo struct{}`}, - {`type $_ struct{$*_}`, 1, `type foo struct{x int}`}, - {`type $_ struct{$*_}`, 0, `type foo int`}, - {`type $_ struct{$*_; Foo; $*_}`, 1, `type foo struct{Foo}`}, - {`type $_ struct{$*_; Foo; $*_}`, 1, `type foo struct{x int; Foo}`}, - {`type $_ struct{$*_; Foo; $*_}`, 1, `type foo struct{Foo; x int}`}, - {`type $_ struct{$*_; Foo; $*_}`, 1, `type foo struct{x int; Foo; y int}`}, - {`type $_ struct{$*_; Foo; $*_}`, 0, `type foo struct{*Foo}`}, - {`type $_ struct{$*_; Foo; $*_}`, 0, `type foo struct{x int}`}, - - // Value specs. - {`$_ int`, 1, `var a int`}, - {`$_ int`, 0, `var a bool`}, - {`$_ int = 5`, 1, `var x int = 5`}, - {`$_ int = 5`, 0, `var x int`}, - {`$_ int = 5`, 0, `var x int = 0`}, - {`$_ int = 5`, 0, `var x _ = 5`}, - {`$_, $_ int = 10, 20`, 1, `var x, y int = 10, 20`}, - {`$_, $_ int = 10, 20`, 0, `var x, y int = f()`}, - {`$_, $_ int = 10, 20`, 0, `var x, y int = _, 20`}, - {`$_, $_ int = 10, 20`, 0, `var x, y int = 10, _`}, - {`$_, $_ int = 10, 20`, 0, `var x int = 10`}, - {`$_, $_ int = 10, 20`, 0, `var x, y = 10, 20`}, - // TODO: consider these. - {`$_ int`, 0, `var a int = 3`}, - {`$_ int`, 0, `var a, b int`}, - {`$_ int`, 0, `func(i int) { println(i) }`}, - - // File. - {`package foo`, 1, `package foo;`}, - {`package foo`, 0, `package bar;`}, - } - - for i := range tests { - test := tests[i] - t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) { - state := NewMatcherState() - fset := token.NewFileSet() - testPattern := unwrapPattern(test.pat) - pat, _, err := Compile(fset, testPattern, isStrict(test.pat)) - if err != nil { - t.Errorf("compile `%s`: %v", test.pat, err) - return - } - target := testParseNode(t, token.NewFileSet(), test.input) - if err != nil { - t.Errorf("parse target `%s`: %v", test.input, err) - return - } - matches := 0 - testAllMatches(pat, &state, target, func(m MatchData) { - matches++ - }) - if matches != test.numMatches { - t.Errorf("test `%s`:\ntarget: `%s`\nhave: %v\nwant: %v", - test.pat, test.input, matches, test.numMatches) - } - }) - } -} - -func testAllMatches(p *Pattern, state *MatcherState, target ast.Node, cb func(MatchData)) { - visit := func(n ast.Node) bool { - if n == nil { - return false - } - p.MatchNode(state, n, cb) - return true - } - ast.Inspect(target, visit) -} diff --git a/internal/gogrep/operation_string.go b/internal/gogrep/operation_string.go deleted file mode 100644 index 898cc8d5..00000000 --- a/internal/gogrep/operation_string.go +++ /dev/null @@ -1,140 +0,0 @@ -// 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[opStdlibPkg-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[opFieldList-98] - _ = x[opUnnamedField-99] - _ = x[opSimpleField-100] - _ = x[opField-101] - _ = x[opMultiField-102] - _ = x[opValueSpec-103] - _ = x[opValueInitSpec-104] - _ = x[opTypedValueInitSpec-105] - _ = x[opTypedValueSpec-106] - _ = x[opTypeSpec-107] - _ = x[opTypeAliasSpec-108] - _ = x[opFuncDecl-109] - _ = x[opMethodDecl-110] - _ = x[opFuncProtoDecl-111] - _ = x[opMethodProtoDecl-112] - _ = x[opDeclStmt-113] - _ = x[opConstDecl-114] - _ = x[opVarDecl-115] - _ = x[opTypeDecl-116] - _ = x[opEmptyPackage-117] -} - -const _operation_name = "InvalidNodeNamedNodeNodeSeqNamedNodeSeqOptNodeNamedOptNodeFieldNodeNamedFieldNodeMultiStmtMultiExprMultiDeclEndBasicLitStrictIntLitStrictFloatLitStrictCharLitStrictStringLitStrictComplexLitIdentStdlibPkgIndexExprSliceExprSliceFromExprSliceToExprSliceFromToExprSliceToCapExprSliceFromToCapExprFuncLitCompositeLitTypedCompositeLitSimpleSelectorExprSelectorExprTypeAssertExprTypeSwitchAssertExprStructTypeInterfaceTypeVoidFuncTypeFuncTypeArrayTypeSliceTypeMapTypeChanTypeKeyValueExprEllipsisTypedEllipsisStarExprUnaryExprBinaryExprParenExprArgListSimpleArgListVariadicCallExprNonVariadicCallExprCallExprAssignStmtMultiAssignStmtBranchStmtSimpleLabeledBranchStmtLabeledBranchStmtSimpleLabeledStmtLabeledStmtBlockStmtExprStmtGoStmtDeferStmtSendStmtEmptyStmtIncDecStmtReturnStmtIfStmtIfInitStmtIfElseStmtIfInitElseStmtIfNamedOptStmtIfNamedOptElseStmtSwitchStmtSwitchTagStmtSwitchInitStmtSwitchInitTagStmtSelectStmtTypeSwitchStmtTypeSwitchInitStmtCaseClauseDefaultCaseClauseCommClauseDefaultCommClauseForStmtForPostStmtForCondStmtForCondPostStmtForInitStmtForInitPostStmtForInitCondStmtForInitCondPostStmtRangeStmtRangeKeyStmtRangeKeyValueStmtFieldListUnnamedFieldSimpleFieldFieldMultiFieldValueSpecValueInitSpecTypedValueInitSpecTypedValueSpecTypeSpecTypeAliasSpecFuncDeclMethodDeclFuncProtoDeclMethodProtoDeclDeclStmtConstDeclVarDeclTypeDeclEmptyPackage" - -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, 203, 212, 221, 234, 245, 260, 274, 292, 299, 311, 328, 346, 358, 372, 392, 402, 415, 427, 435, 444, 453, 460, 468, 480, 488, 501, 509, 518, 528, 537, 544, 557, 573, 592, 600, 610, 625, 635, 658, 675, 692, 703, 712, 720, 726, 735, 743, 752, 762, 772, 778, 788, 798, 812, 826, 844, 854, 867, 881, 898, 908, 922, 940, 950, 967, 977, 994, 1001, 1012, 1023, 1038, 1049, 1064, 1079, 1098, 1107, 1119, 1136, 1145, 1157, 1168, 1173, 1183, 1192, 1205, 1223, 1237, 1245, 1258, 1266, 1276, 1289, 1304, 1312, 1321, 1328, 1336, 1348} - -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/internal/gogrep/operations.gen.go b/internal/gogrep/operations.gen.go deleted file mode 100644 index 7f6471bb..00000000 --- a/internal/gogrep/operations.gen.go +++ /dev/null @@ -1,1493 +0,0 @@ -// Code generated "gen_operations.go"; DO NOT EDIT. - -package gogrep - -import ( - "github.com/quasilyte/go-ruleguard/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 name - opStdlibPkg 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: Unknown - // Args: fields... - opFieldList operation = 98 - - // Tag: Unknown - // Args: typ - // Example: type - opUnnamedField operation = 99 - - // Tag: Unknown - // Args: typ - // Example: name type - // ValueIndex: strings | field name - opSimpleField operation = 100 - - // Tag: Unknown - // Args: name typ - // Example: $name type - opField operation = 101 - - // Tag: Unknown - // Args: names... typ - // Example: name1, name2 type - opMultiField operation = 102 - - // Tag: ValueSpec - // Args: value - opValueSpec operation = 103 - - // Tag: ValueSpec - // Args: lhs... rhs... - // Example: lhs = rhs - opValueInitSpec operation = 104 - - // Tag: ValueSpec - // Args: lhs... type rhs... - // Example: lhs typ = rhs - opTypedValueInitSpec operation = 105 - - // Tag: ValueSpec - // Args: lhs... type - // Example: lhs typ - opTypedValueSpec operation = 106 - - // Tag: TypeSpec - // Args: name type - // Example: name type - opTypeSpec operation = 107 - - // Tag: TypeSpec - // Args: name type - // Example: name = type - opTypeAliasSpec operation = 108 - - // Tag: FuncDecl - // Args: name type block - opFuncDecl operation = 109 - - // Tag: FuncDecl - // Args: recv name type block - opMethodDecl operation = 110 - - // Tag: FuncDecl - // Args: name type - opFuncProtoDecl operation = 111 - - // Tag: FuncDecl - // Args: recv name type - opMethodProtoDecl operation = 112 - - // Tag: DeclStmt - // Args: decl - opDeclStmt operation = 113 - - // Tag: GenDecl - // Args: valuespecs... - opConstDecl operation = 114 - - // Tag: GenDecl - // Args: valuespecs... - opVarDecl operation = 115 - - // Tag: GenDecl - // Args: typespecs... - opTypeDecl operation = 116 - - // Tag: File - // Args: name - opEmptyPackage operation = 117 -) - -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, - }, - opStdlibPkg: { - 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, - }, - 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, - }, - opEmptyPackage: { - Tag: nodetag.File, - NumArgs: 1, - ValueKind: emptyValue, - ExtraValueKind: emptyValue, - VariadicMap: 0, // 0 - SliceIndex: -1, - }, -} diff --git a/internal/gogrep/parse.go b/internal/gogrep/parse.go deleted file mode 100644 index 2cd73934..00000000 --- a/internal/gogrep/parse.go +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright (c) 2017, Daniel Martí -// 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, *ast.File, 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, nil, fmt.Errorf("empty source code") - } - var mainErr error - - // 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, f, 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], f, nil - } - return ExprSlice(cl.Elts), f, 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], f, nil - } - return stmtSlice(bl.List), f, 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], f, nil - } - return declSlice(f.Decls), f, nil - } - - // try as a whole file - if f, err := parser.ParseFile(fset, "", src, 0); err == nil && noBadNodes(f) { - return f, 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, f, nil - } - - // value specs - asValSpec := execTmpl(tmplValSpec, src) - if f, err := parser.ParseFile(fset, "", asValSpec, 0); err == nil && noBadNodes(f) { - vs := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec) - return vs, f, nil - } - - return nil, 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, ""}) - toks = append(toks, 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] - 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{} -} diff --git a/internal/gogrep/slices.go b/internal/gogrep/slices.go deleted file mode 100644 index 13775a81..00000000 --- a/internal/gogrep/slices.go +++ /dev/null @@ -1,58 +0,0 @@ -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() } diff --git a/nodetag/nodetag.go b/nodetag/nodetag.go deleted file mode 100644 index 7c0408b5..00000000 --- a/nodetag/nodetag.go +++ /dev/null @@ -1,278 +0,0 @@ -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/ruleguard/filters.go b/ruleguard/filters.go index 9bf50dab..471e9364 100644 --- a/ruleguard/filters.go +++ b/ruleguard/filters.go @@ -7,12 +7,12 @@ import ( "go/types" "path/filepath" - "github.com/quasilyte/go-ruleguard/internal/gogrep" "github.com/quasilyte/go-ruleguard/internal/xtypes" - "github.com/quasilyte/go-ruleguard/nodetag" "github.com/quasilyte/go-ruleguard/ruleguard/quasigo" "github.com/quasilyte/go-ruleguard/ruleguard/textmatch" "github.com/quasilyte/go-ruleguard/ruleguard/typematch" + "github.com/quasilyte/gogrep" + "github.com/quasilyte/gogrep/nodetag" ) const filterSuccess = matchFilterResult("") diff --git a/ruleguard/gorule.go b/ruleguard/gorule.go index cfc7b70d..90963f43 100644 --- a/ruleguard/gorule.go +++ b/ruleguard/gorule.go @@ -6,9 +6,9 @@ import ( "go/types" "regexp" - "github.com/quasilyte/go-ruleguard/internal/gogrep" - "github.com/quasilyte/go-ruleguard/nodetag" "github.com/quasilyte/go-ruleguard/ruleguard/quasigo" + "github.com/quasilyte/gogrep" + "github.com/quasilyte/gogrep/nodetag" ) type goRuleSet struct { diff --git a/ruleguard/ir_loader.go b/ruleguard/ir_loader.go index 272ab7fe..1aaaf0ee 100644 --- a/ruleguard/ir_loader.go +++ b/ruleguard/ir_loader.go @@ -11,13 +11,13 @@ import ( "io/ioutil" "regexp" - "github.com/quasilyte/go-ruleguard/internal/gogrep" - "github.com/quasilyte/go-ruleguard/nodetag" "github.com/quasilyte/go-ruleguard/ruleguard/goutil" "github.com/quasilyte/go-ruleguard/ruleguard/ir" "github.com/quasilyte/go-ruleguard/ruleguard/quasigo" "github.com/quasilyte/go-ruleguard/ruleguard/textmatch" "github.com/quasilyte/go-ruleguard/ruleguard/typematch" + "github.com/quasilyte/gogrep" + "github.com/quasilyte/gogrep/nodetag" ) type irLoaderConfig struct { @@ -316,7 +316,13 @@ func (l *irLoader) loadSyntaxRule(resultProto goRule, filterInfo filterInfo, rul result := resultProto result.line = line - pat, info, err := gogrep.Compile(l.gogrepFset, src, false) + gogrepConfig := gogrep.CompileConfig{ + Fset: l.gogrepFset, + Src: src, + Strict: false, + WithTypes: true, + } + pat, info, err := gogrep.Compile(gogrepConfig) if err != nil { return l.errorf(rule.Line, err, "parse match pattern") } diff --git a/ruleguard/match_data.go b/ruleguard/match_data.go index c9d64aff..3bf3bf5a 100644 --- a/ruleguard/match_data.go +++ b/ruleguard/match_data.go @@ -3,7 +3,7 @@ package ruleguard import ( "go/ast" - "github.com/quasilyte/go-ruleguard/internal/gogrep" + "github.com/quasilyte/gogrep" ) // matchData is used to handle both regexp and AST match sets in the same way. diff --git a/ruleguard/ruleguard_test.go b/ruleguard/ruleguard_test.go index ad3256a3..e32d7a24 100644 --- a/ruleguard/ruleguard_test.go +++ b/ruleguard/ruleguard_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/quasilyte/go-ruleguard/internal/gogrep" + "github.com/quasilyte/gogrep" ) func TestRenderMessage(t *testing.T) { diff --git a/ruleguard/runner.go b/ruleguard/runner.go index 09cbd406..4f1aabdf 100644 --- a/ruleguard/runner.go +++ b/ruleguard/runner.go @@ -12,9 +12,9 @@ import ( "strconv" "strings" - "github.com/quasilyte/go-ruleguard/internal/gogrep" - "github.com/quasilyte/go-ruleguard/nodetag" "github.com/quasilyte/go-ruleguard/ruleguard/goutil" + "github.com/quasilyte/gogrep" + "github.com/quasilyte/gogrep/nodetag" ) type rulesRunner struct {