func (m Mocks) Output(pkg, dir string, chanSize int, dest io.Writer) error { if _, err := dest.Write([]byte(commentHeader)); err != nil { return err } fset := token.NewFileSet() f := &ast.File{ Name: &ast.Ident{Name: pkg}, Decls: m.decls(chanSize), } var b bytes.Buffer format.Node(&b, fset, f) // TODO: Determine why adding imports without creating a new ast file // will only allow one import to be printed to the file. fset = token.NewFileSet() file, err := parser.ParseFile(fset, pkg, &b, 0) if err != nil { return err } file, fset, err = addImports(file, fset, dir) if err != nil { return err } return format.Node(dest, fset, file) }
func (b *builder) merge() ([]byte, error) { var buf bytes.Buffer if err := b.tpl.Execute(&buf, b); err != nil { return nil, err } f, err := parser.ParseFile(b.fset, "", &buf, 0) if err != nil { return nil, err } // b.imports(f) b.deleteImports(f) b.files["main.go"] = f pkg, _ := ast.NewPackage(b.fset, b.files, nil, nil) pkg.Name = "main" ret, err := ast.MergePackageFiles(pkg, 0), nil if err != nil { return nil, err } // @TODO: we reread the file, probably something goes wrong with position buf.Reset() if err = format.Node(&buf, b.fset, ret); err != nil { return nil, err } ret, err = parser.ParseFile(b.fset, "", buf.Bytes(), 0) if err != nil { return nil, err } for _, spec := range b.imports { var name string if spec.Name != nil { name = spec.Name.Name } ipath, _ := strconv.Unquote(spec.Path.Value) addImport(b.fset, ret, name, ipath) } buf.Reset() if err := format.Node(&buf, b.fset, ret); err != nil { return nil, err } return buf.Bytes(), nil }
func CodeBytes(fset *token.FileSet, node interface{}) ([]byte, error) { var buf bytes.Buffer if err := format.Node(&buf, fset, node); err != nil { return nil, err } return buf.Bytes(), nil }
/* * Given a file path, rewrites any tests in the Ginkgo format. * First, we parse the AST, and update the imports declaration. * Then, we walk the first child elements in the file, returning tests to rewrite. * A top level init func is declared, with a single Describe func inside. * Then the test functions to rewrite are inserted as It statements inside the Describe. * Finally we walk the rest of the file, replacing other usages of *testing.T * Once that is complete, we write the AST back out again to its file. */ func rewriteTestsInFile(pathToFile string) { fileSet := token.NewFileSet() rootNode, err := parser.ParseFile(fileSet, pathToFile, nil, 0) if err != nil { panic(fmt.Sprintf("Error parsing test file '%s':\n%s\n", pathToFile, err.Error())) } addGinkgoImports(rootNode) removeTestingImport(rootNode) topLevelInitFunc := createInitBlock() describeBlock := createDescribeBlock() topLevelInitFunc.Body.List = append(topLevelInitFunc.Body.List, describeBlock) for _, testFunc := range findTestFuncs(rootNode) { rewriteTestFuncAsItStatement(testFunc, rootNode, describeBlock) } rootNode.Decls = append(rootNode.Decls, topLevelInitFunc) rewriteOtherFuncsToUseGinkgoT(rootNode.Decls) walkNodesInRootNodeReplacingTestingT(rootNode) var buffer bytes.Buffer if err = format.Node(&buffer, fileSet, rootNode); err != nil { panic(fmt.Sprintf("Error formatting ast node after rewriting tests.\n%s\n", err.Error())) } fileInfo, err := os.Stat(pathToFile) if err != nil { panic(fmt.Sprintf("Error stat'ing file: %s\n", pathToFile)) } ioutil.WriteFile(pathToFile, buffer.Bytes(), fileInfo.Mode()) return }
func (m Mocks) Output(pkg string, chanSize int, dest io.Writer) error { f := &ast.File{ Name: &ast.Ident{Name: pkg}, Decls: m.decls(chanSize), } return format.Node(dest, token.NewFileSet(), f) }
func TestExamples(t *testing.T) { fset := token.NewFileSet() file, err := parser.ParseFile(fset, "test.go", strings.NewReader(exampleTestFile), parser.ParseComments) if err != nil { t.Fatal(err) } for i, e := range doc.Examples(file) { c := exampleTestCases[i] if e.Name != c.Name { t.Errorf("got Name == %q, want %q", e.Name, c.Name) } if w := c.Play; w != "" { var g string // hah if e.Play == nil { g = "<nil>" } else { var buf bytes.Buffer if err := format.Node(&buf, fset, e.Play); err != nil { t.Fatal(err) } g = buf.String() } if g != w { t.Errorf("%s: got Play == %q, want %q", c.Name, g, w) } } if g, w := e.Output, c.Output; g != w { t.Errorf("%s: got Output == %q, want %q", c.Name, g, w) } } }
// Gen generates Go code for a set of table mappings. func (c *Code) Gen(mapper *Map, pkg string, out io.Writer) { data := struct { Package string Imports []importSpec TableMaps []tableMapTmpl }{ Package: pkg, Imports: mapper.Imports(), } for i, tableMap := range *mapper { log.Printf("%d: generating map %s -> %s", i, tableMap.Table, tableMap.Struct) data.TableMaps = append(data.TableMaps, c.genMapper(tableMap)) } if err := c.tmpl.Execute(c.buf, data); err != nil { // TODO(paulsmith): return error log.Fatal(err) } // gofmt fset := token.NewFileSet() ast, err := parser.ParseFile(fset, "", c.buf.Bytes(), parser.ParseComments) if err != nil { // TODO(paulsmith): return error log.Fatal(err) } err = format.Node(out, fset, ast) if err != nil { // TODO(paulsmith): return error log.Fatal(err) } }
func gofmt(n interface{}) string { gofmtBuf.Reset() if err := format.Node(&gofmtBuf, fset, n); err != nil { return "<" + err.Error() + ">" } return gofmtBuf.String() }
// FormatCode runs "goimports -w" on the source file. func (f *SourceFile) FormatCode() error { // Parse file into AST fset := token.NewFileSet() file, err := parser.ParseFile(fset, f.Abs(), nil, parser.ParseComments) if err != nil { content, _ := ioutil.ReadFile(f.Abs()) var buf bytes.Buffer scanner.PrintError(&buf, err) return fmt.Errorf("%s\n========\nContent:\n%s", buf.String(), content) } // Clean unused imports imports := astutil.Imports(fset, file) for _, group := range imports { for _, imp := range group { path := strings.Trim(imp.Path.Value, `"`) if !astutil.UsesImport(file, path) { if imp.Name != nil { astutil.DeleteNamedImport(fset, file, imp.Name.Name, path) } else { astutil.DeleteImport(fset, file, path) } } } } ast.SortImports(fset, file) // Open file to be written w, err := os.OpenFile(f.Abs(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) if err != nil { return err } defer w.Close() // Write formatted code without unused imports return format.Node(w, fset, file) }
// nodeString returns a string representation of n. func nodeString(n ast.Node) string { var buf bytes.Buffer if err := format.Node(&buf, fset, n); err != nil { log.Fatal(err) // should always succeed } return buf.String() }
func TranspileFile(goFilename, phpFilename, phpStr string, gosrc io.Writer) error { parser := parser.NewParser() file, err := parser.Parse(phpFilename, phpStr) if err != nil { return fmt.Errorf("found errors while parsing %s: %s", phpFilename, err) } tg := Togo{currentScope: parser.FileSet.Scope} nodes := []goast.Node{} for _, node := range tg.beginScope(tg.currentScope) { nodes = append(nodes, node) } for _, phpNode := range file.Nodes { nodes = append(nodes, tg.ToGoStmt(phpNode.(phpast.Statement))) } buf := &bytes.Buffer{} if err = format.Node(buf, token.NewFileSet(), File(phpFilename[:len(phpFilename)-4], nodes...)); err != nil { return fmt.Errorf("error while formatting %s: %s", phpFilename, err) } imported, err := imports.Process(goFilename, buf.Bytes(), &imports.Options{AllErrors: true, Comments: true, TabIndent: true, TabWidth: 8}) if err != nil { return fmt.Errorf("error while getting imports for %s: %s", phpFilename, err) } _, err = gosrc.Write(imported) return err }
func print(t *testing.T, name string, f *ast.File) string { var buf bytes.Buffer if err := format.Node(&buf, fset, f); err != nil { t.Fatalf("%s gofmt: %v", name, err) } return string(buf.Bytes()) }
// FormatCode runs "goimports -w" on the source file. func (f *SourceFile) FormatCode() error { if NoFormat { return nil } // Parse file into AST fset := token.NewFileSet() file, err := parser.ParseFile(fset, f.Abs(), nil, parser.ParseComments) if err != nil { return err } // Clean unused imports imports := astutil.Imports(fset, file) for _, group := range imports { for _, imp := range group { path := strings.Trim(imp.Path.Value, `"`) if !astutil.UsesImport(file, path) { astutil.DeleteImport(fset, file, path) } } } ast.SortImports(fset, file) // Open file to be written w, err := os.OpenFile(f.Abs(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) if err != nil { return err } defer w.Close() // Write formatted code without unused imports return format.Node(w, fset, file) }
// Rewrite modifies the AST to rewrite import statements and package import comments. // src should be compatible with go/parser/#ParseFile: // (The type of the argument for the src parameter must be string, []byte, or io.Reader.) // // return of nil, nil (no result, no error) means no changes are needed func Rewrite(fname string, src interface{}, prefix string, remove bool) (buf *bytes.Buffer, err error) { // Create the AST by parsing src. fset := token.NewFileSet() // positions are relative to fset f, err := parser.ParseFile(fset, fname, src, parser.ParseComments) if err != nil { log.Printf("Error parsing file %s, source: [%s], error: %s", fname, src, err) return nil, err } // normalize the prefix ending with a trailing slash if prefix[len(prefix)-1] != '/' { prefix += "/" } changed, err := RewriteImports(f, prefix, remove) if err != nil { log.Printf("Error rewriting imports in the AST: file %s - %s", fname, err) return nil, err } changed2, err := RewriteImportComments(f, fset, prefix, remove) if err != nil { log.Printf("Error rewriting import comments in the AST: file %s - %s", fname, err) return nil, err } if !changed && !changed2 { return nil, nil } buf = &bytes.Buffer{} err = format.Node(buf, fset, f) return buf, err }
func (p *Presentation) example_htmlFunc(info *PageInfo, funcName string) string { var buf bytes.Buffer for _, eg := range info.Examples { name := stripExampleSuffix(eg.Name) if name != funcName { continue } // print code cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments} code := p.node_htmlFunc(info, cnode, true) out := eg.Output wholeFile := true // Additional formatting if this is a function body. if n := len(code); n >= 2 && code[0] == '{' && code[n-1] == '}' { wholeFile = false // remove surrounding braces code = code[1 : n-1] // unindent code = strings.Replace(code, "\n ", "\n", -1) // remove output comment if loc := exampleOutputRx.FindStringIndex(code); loc != nil { code = strings.TrimSpace(code[:loc[0]]) } } // Write out the playground code in standard Go style // (use tabs, no comment highlight, etc). play := "" if eg.Play != nil && p.ShowPlayground { var buf bytes.Buffer if err := format.Node(&buf, info.FSet, eg.Play); err != nil { log.Print(err) } else { play = buf.String() } } // Drop output, as the output comment will appear in the code. if wholeFile && play == "" { out = "" } if p.ExampleHTML == nil { out = "" return "" } err := p.ExampleHTML.Execute(&buf, struct { Name, Doc, Code, Play, Output string Share bool }{eg.Name, eg.Doc, code, play, out, info.Share}) if err != nil { log.Print(err) } } return buf.String() }
func TestFilterDuplicates(t *testing.T) { // parse input fset := token.NewFileSet() file, err := parser.ParseFile(fset, "", input, 0) if err != nil { t.Fatal(err) } // create package files := map[string]*ast.File{"": file} pkg, err := ast.NewPackage(fset, files, nil, nil) if err != nil { t.Fatal(err) } // filter merged := ast.MergePackageFiles(pkg, ast.FilterFuncDuplicates) // pretty-print var buf bytes.Buffer if err := format.Node(&buf, fset, merged); err != nil { t.Fatal(err) } output := buf.String() if output != golden { t.Errorf("incorrect output:\n%s", output) } }
// Parse the arguments string Template(A, B, C) func parseTemplateAndArgs(s string) (name string, args []string) { expr, err := parser.ParseExpr(s) if err != nil { fatalf("Failed to parse %q: %v", s, err) } debugf("expr = %#v\n", expr) callExpr, ok := expr.(*ast.CallExpr) if !ok { fatalf("Failed to parse %q: expecting Identifier(...)", s) } debugf("fun = %#v", callExpr.Fun) fn, ok := callExpr.Fun.(*ast.Ident) if !ok { fatalf("Failed to parse %q: expecting Identifier(...)", s) } name = fn.Name for i, arg := range callExpr.Args { var buf bytes.Buffer debugf("arg[%d] = %#v", i, arg) format.Node(&buf, token.NewFileSet(), arg) s := buf.String() debugf("parsed = %q", s) args = append(args, s) } return }
func gofmtFile(f *ast.File) ([]byte, error) { var buf bytes.Buffer if err := format.Node(&buf, fset, f); err != nil { return nil, err } return buf.Bytes(), nil }
func rewriteFile(fset *token.FileSet, f *ast.File, filename string) error { var buf bytes.Buffer if err := format.Node(&buf, fset, f); err != nil { return fmt.Errorf("failed to pretty-print syntax tree: %v", err) } return ioutil.WriteFile(filename, buf.Bytes(), 0644) }
func annotate(file string) { fset = token.NewFileSet() f, err := parser.ParseFile(fset, file, nil, parser.ParseComments) if err != nil { log.Fatal(err) } for _, imp := range f.Imports { if imp.Name != nil && imp.Name.Name == importName { log.Printf(`"%s" already imported. skipping %s`, importName, file) return } if imp.Path.Value == importPath { log.Printf(`"%s", already imported. skipping %s`, importPath, file) return } } edits := editList{packageName: f.Name.Name} // insert our import directly after the package line edits.Add(int(f.Name.End()), []byte(importStmt)) ast.Inspect(f, edits.inspect) var buf bytes.Buffer if err := format.Node(&buf, fset, f); err != nil { log.Fatal("format.Node", err) } data := buf.Bytes() var pos int var out []byte for _, e := range edits.edits { out = append(out, data[pos:e.pos]...) out = append(out, []byte(e.val)...) pos = e.pos } out = append(out, data[pos:]...) // it's easier to append the setup code at the end out = append(out, []byte(setup)...) src, err := format.Source(out) if err != nil { log.Fatal("format.Source ", err) } if !writeFiles { fmt.Println(string(src)) return } err = ioutil.WriteFile(file, src, 0) if err != nil { log.Fatal(err) } }
// gofmt takes the given, valid, Go AST and returns a // canonically-formatted go program in a byte-array, or an error. func gofmt(f *ast.File) ([]byte, error) { fset := token.NewFileSet() var buf bytes.Buffer if err := format.Node(&buf, fset, f); err != nil { return nil, err } return buf.Bytes(), nil }
func CreateSourceCode(astFile *ast.File) ([]byte, error) { sourceCode := &bytes.Buffer{} err := format.Node(sourceCode, token.NewFileSet(), astFile) if err != nil { return nil, err } return sourceCode.Bytes(), nil }
// rewrite reads, modifies, and writes filename, replacing all imports // of packages P in noncanonical by noncanonical[P]. // It records in used which noncanonical packages were imported. // used[P]=="" indicates that P was imported but its canonical path is unknown. func rewriteFile(filename string, noncanonical map[string]*build.Package, used map[string]bool) error { fset := token.NewFileSet() f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments) if err != nil { return err } var changed bool for _, imp := range f.Imports { impPath, err := strconv.Unquote(imp.Path.Value) if err != nil { log.Printf("%s: bad import spec %q: %v", fset.Position(imp.Pos()), imp.Path.Value, err) continue } p, ok := noncanonical[impPath] if !ok { continue // import path is canonical } used[impPath] = true if p == nil { // The canonical path is unknown. // Show the offending import. // TODO(adonovan): should we show the actual source text? fmt.Fprintf(stderr, "\t%s:%d: import %q\n", shortPath(filename), fset.Position(imp.Pos()).Line, impPath) continue } changed = true imp.Path.Value = strconv.Quote(p.ImportComment) // Add a renaming import if necessary. // // This is a guess at best. We can't see whether a 'go // get' of the canonical import path would have the same // name or not. Assume it's the last segment. // // TODO(adonovan): should we make an HTTP request? newBase := path.Base(p.ImportComment) if imp.Name == nil && newBase != p.Name { imp.Name = &ast.Ident{Name: p.Name} } } if changed && !*dryrun { var buf bytes.Buffer if err := format.Node(&buf, fset, f); err != nil { return fmt.Errorf("%s: couldn't format file: %v", filename, err) } return writeFile(filename, buf.Bytes(), 0644) } return nil }
// This example illustrates how to remove a variable declaration // in a Go program while maintaining correct comment association // using an ast.CommentMap. func ExampleCommentMap() { // src is the input for which we create the AST that we // are going to manipulate. src := ` // This is the package comment. package main // This comment is associated with the hello constant. const hello = "Hello, World!" // line comment 1 // This comment is associated with the foo variable. var foo = hello // line comment 2 // This comment is associated with the main function. func main() { fmt.Println(hello) // line comment 3 } ` // Create the AST by parsing src. fset := token.NewFileSet() // positions are relative to fset f, err := parser.ParseFile(fset, "src.go", src, parser.ParseComments) if err != nil { panic(err) } // Create an ast.CommentMap from the ast.File's comments. // This helps keeping the association between comments // and AST nodes. cmap := ast.NewCommentMap(fset, f, f.Comments) // Remove the first variable declaration from the list of declarations. f.Decls = removeFirstVarDecl(f.Decls) // Use the comment map to filter comments that don't belong anymore // (the comments associated with the variable declaration), and create // the new comments list. f.Comments = cmap.Filter(f).Comments() // Print the modified AST. var buf bytes.Buffer if err := format.Node(&buf, fset, f); err != nil { panic(err) } fmt.Printf("%s", buf.Bytes()) // output: // // This is the package comment. // package main // // // This comment is associated with the hello constant. // const hello = "Hello, World!" // line comment 1 // // // This comment is associated with the main function. // func main() { // fmt.Println(hello) // line comment 3 // } }
// Format source from reader to writer func Format(fname string, r io.Reader, w io.Writer) error { fset := token.NewFileSet() f, err := parser.ParseFile(fset, fname, r, parser.ParseComments) if err != nil { return err } return format.Node(w, fset, f) }
func (b *BlockStmt) Format() string { var buf bytes.Buffer fset := token.NewFileSet() for i := range b.Children { format.Node(&buf, fset, b.Node[i]) fmt.Fprintln(&buf) } return buf.String() }
func (gen CodeGenerator) GenerateFake() (string, error) { buf := new(bytes.Buffer) err := format.Node(buf, token.NewFileSet(), gen.sourceFile()) if err != nil { return "", err } code, err := imports.Process("", buf.Bytes(), nil) return commentLine() + prettifyCode(string(code)), err }
func Format(n ast.Node) string { var buf bytes.Buffer fset := token.NewFileSet() format.Node(&buf, fset, n) str := buf.String() if strings.HasSuffix(str, "\n") { str = str[:len(str)-1] } return str }
func main() { if len(os.Args) <= 1 { return } resp, err := http.Get(raw) if err != nil { log.Fatal(err) } // parser fset := token.NewFileSet() f, err := parser.ParseFile(fset, "", resp.Body, 0) if err != nil { log.Fatal(err) } // remove Init() LOOP: for k := range f.Decls { switch f.Decls[k].(type) { case *ast.FuncDecl: decl := f.Decls[k].(*ast.FuncDecl) if decl.Name.Name == "Init" { f.Decls = append(f.Decls[:k], f.Decls[k+1:]...) break LOOP } } } // create file out, err := os.Create("services.go") if err != nil { log.Fatal(err) } // rewrite format.Node(out, fset, f) //add stub funcMap := template.FuncMap{ "Name": func(s string) string { a := []rune(s) a[0] = unicode.ToUpper(a[0]) return string(a) }, } tmpl, err := template.New("proto.tmpl").Funcs(funcMap).Parse(t) if err != nil { log.Fatal(err) } err = tmpl.Execute(out, os.Args[1:]) if err != nil { log.Fatal(err) } }
func source(expect func(interface{}) *expect.Expect, pkg string, decls []ast.Decl, scope *ast.Scope) string { buf := bytes.Buffer{} f := &ast.File{ Name: &ast.Ident{Name: pkg}, Decls: decls, Scope: scope, } err := format.Node(&buf, token.NewFileSet(), f) expect(err).To.Be.Nil() return buf.String() }