This repository has been archived by the owner on Jun 9, 2021. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
See #32.
- Loading branch information
Showing
47 changed files
with
2,977 additions
and
2,539 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
# To prevent CRLF breakages on Windows for fragile files, like testdata. | ||
* -text | ||
|
||
# Don't show bundled base64 strings in git diff/grep. | ||
bundle.go -diff -text |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/gogrep |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// +build gogrep | ||
|
||
package builtin | ||
|
||
import "mvdan.cc/gogrep/nls" | ||
|
||
func excludeParallel(g *nls.G) { | ||
// g.With(nls.All(`$*body`)) | ||
// g.With(nls.All(`$*body`), nls.All(`{ $*_; }`), nls.Replace(`{}`)) | ||
g.Excluding(`t.Parallel()`) | ||
} | ||
|
||
func NonParallelTests(g *nls.G) { | ||
// TODO: include the case where a sub-test calls Parallel, but the | ||
// parent test does not. | ||
g.All(`func $f(t *testing.T) { $*body }`) | ||
excludeParallel(g) | ||
g.Report("$f is not parallel") | ||
} | ||
|
||
func NonParallelSubtests(g *nls.G) { | ||
// TODO: include the case where a sub-test calls Parallel, but the | ||
// parent test does not. | ||
g.All(`t.Run($n, func(t *testing.T) { $*body })`) | ||
excludeParallel(g) | ||
g.Report("subtest $n is not parallel") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// +build ignore | ||
|
||
package main | ||
|
||
import ( | ||
"encoding/base64" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"text/template" | ||
) | ||
|
||
func main() { | ||
if err := run(); err != nil { | ||
fmt.Fprintln(os.Stderr, err) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
var globs = []string{ | ||
"go.*", | ||
// TODO: use 'go list' to include deps automatically | ||
"mainpkg/*.go", | ||
"nls/*.go", | ||
"gsyntax/*.go", | ||
"internal/load/*.go", | ||
} | ||
|
||
type bundledFile struct{ Name, Content string } | ||
|
||
var tmpl = template.Must(template.New("").Parse(` | ||
package main | ||
var bundledFiles = [...]struct{ | ||
name, encContent string | ||
}{ | ||
{{ range $_, $f := . }} { {{ printf "%q" $f.Name }}, {{ printf "%q" $f.Content }} }, | ||
{{ end }} | ||
} | ||
`)) | ||
|
||
func run() error { | ||
var files []bundledFile | ||
for _, glob := range globs { | ||
matches, err := filepath.Glob(glob) | ||
if err != nil { | ||
return err | ||
} | ||
if len(matches) == 0 { | ||
return fmt.Errorf("no matches for %q", glob) | ||
} | ||
for _, match := range matches { | ||
if strings.HasSuffix(match, "_test.go") { | ||
continue | ||
} | ||
content, err := ioutil.ReadFile(match) | ||
if err != nil { | ||
return err | ||
} | ||
files = append(files, bundledFile{ | ||
Name: match, | ||
Content: base64.RawStdEncoding.EncodeToString(content), | ||
}) | ||
} | ||
} | ||
f, err := os.Create("bundle.go") | ||
if err != nil { | ||
return err | ||
} | ||
if err := tmpl.Execute(f, files); err != nil { | ||
return err | ||
} | ||
return f.Close() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
module mvdan.cc/gogrep | ||
|
||
require golang.org/x/tools v0.0.0-20191223235410-3721262b3e7c | ||
require ( | ||
github.com/rogpeppe/go-internal v1.5.1 | ||
golang.org/x/tools v0.0.0-20191223235410-3721262b3e7c | ||
) | ||
|
||
go 1.13 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// Copyright (c) 2019, Daniel Martí <mvdan@mvdan.cc> | ||
// See LICENSE for licensing information | ||
|
||
package gsyntax | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"go/ast" | ||
"go/parser" | ||
"go/scanner" | ||
"go/token" | ||
"text/template" | ||
) | ||
|
||
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 | ||
} | ||
|
||
// ParseAny 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 ParseAny(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 | ||
|
||
// first try as a whole file | ||
if f, err := parser.ParseFile(fset, "", src, 0); err == nil && noBadNodes(f) { | ||
return f, f, nil | ||
} | ||
|
||
// then 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 f, f, nil | ||
} | ||
|
||
// then 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 ExprList(cl.Elts), f, nil | ||
} | ||
|
||
// then try as statements | ||
asStmts := execTmpl(tmplStmts, src) | ||
if f, err := parser.ParseFile(fset, "", asStmts, 0); err == nil && noBadNodes(f) { | ||
bl := f.Decls[0].(*ast.FuncDecl).Body | ||
if len(bl.List) == 1 { | ||
return bl.List[0], f, nil | ||
} | ||
return StmtList(bl.List), f, nil | ||
} else { | ||
// 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}) | ||
} | ||
|
||
// 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 | ||
} |
Oops, something went wrong.