// Node formats node in canonical gofmt style and writes the result to dst. // // The node type must be *ast.File, *printer.CommentedNode, []ast.Decl, // []ast.Stmt, or assignment-compatible to ast.Expr, ast.Decl, ast.Spec, // or ast.Stmt. Node does not modify node. Imports are not sorted for // nodes representing partial source files (i.e., if the node is not an // *ast.File or a *printer.CommentedNode not wrapping an *ast.File). // // The function may return early (before the entire result is written) // and return a formatting error, for instance due to an incorrect AST. // func Node(dst io.Writer, fset *token.FileSet, node interface{}) error { // Determine if we have a complete source file (file != nil). var file *ast.File var cnode *printer.CommentedNode switch n := node.(type) { case *ast.File: file = n case *printer.CommentedNode: if f, ok := n.Node.(*ast.File); ok { file = f cnode = n } } // Sort imports if necessary. if file != nil && hasUnsortedImports(file) { // Make a copy of the AST because ast.SortImports is destructive. // TODO(gri) Do this more efficiently. var buf bytes.Buffer err := config.Fprint(&buf, fset, file) if err != nil { return err } file, err = parser.ParseFile(fset, "", buf.Bytes(), parser.ParseComments) if err != nil { // We should never get here. If we do, provide good diagnostic. return fmt.Errorf("format.Node internal error (%s)", err) } ast.SortImports(fset, file) // Use new file with sorted imports. node = file if cnode != nil { node = &printer.CommentedNode{Node: file, Comments: cnode.Comments} } } return config.Fprint(dst, fset, node) }
// If in == nil, the source is the contents of the file with the given filename. // @argument graph bool wether we want the output for a single component or a graph binary func processFile(filename string, in io.Reader, out io.Writer, stdin bool, graph bool) error { if in == nil { f, err := os.Open(filename) if err != nil { return err } defer f.Close() in = f } src, err := ioutil.ReadAll(in) if err != nil { return err } file, adjust, err := parse(fileSet, filename, src, stdin) if err != nil { return err } // if this isn't an antha file, bail if file.Tok != token.PROTOCOL { return errors.New(filename + " is not a valid Antha file") } ast.SortImports(fileSet, file) var buf bytes.Buffer compiler := &compile.Config{Mode: printerMode, Tabwidth: tabWidth} //TODO probably here is a good fit for a one compiler.init execution err = compiler.Fprint(&buf, fileSet, file) if err != nil { return err } res := buf.Bytes() if adjust != nil { res = adjust(src, res) } comp := compiler.GetFileComponentInfo(fileSet, file) componentLibrary = append(componentLibrary, comp) var filename2 string if graph { st, _ := os.Stat(filename) //we already checked it existed... //we need to create a folder too dirName := strings.TrimSuffix(comp.Name, ".an") //TODO this is wrong, could have a different componentName fi, err := os.Stat(dirName) if err != nil { //does not exist err = os.Mkdir(dirName, 0777) if err != nil { panic(err) return err } fi, err = os.Stat(dirName) if err != nil { return err } } if !fi.IsDir() { return errors.New(dirName + " is not a Directory") } filename2 = dirName + string(os.PathSeparator) + strings.TrimSuffix(st.Name(), ".an") + ".go" } else { filename2 = strings.TrimSuffix(filename, ".an") + ".go" } // save the output as a translated .go file in same location as .an err = ioutil.WriteFile(filename2, res, 0777) if err != nil { return err } if !graph { //get the normal main //dirName is the new directory where we will store the main file dirName := fmt.Sprintf("%s_run", comp.Name) newdir, _ := getPackageRoute(&filename) //packagePath is the route used to import the go generated file packagePath := *newdir var mainBuf bytes.Buffer err = compiler.MainFprint(&mainBuf, fileSet, file, packagePath) if err != nil { return err } res = mainBuf.Bytes() fi, err := os.Stat(dirName) if err != nil { //does not exist err = os.Mkdir(dirName, 0777) if err != nil { fmt.Println(err) return err } fi, err = os.Stat(dirName) if err != nil { return err } } if !fi.IsDir() { return errors.New(dirName + " is not a Directory") } err = ioutil.WriteFile(dirName+"/main.go", res, 0777) if err != nil { return err } } return err }
// Source formats src in canonical gofmt style and returns the result // or an (I/O or syntax) error. src is expected to be a syntactically // correct Go/Antha source file, or a list of Go/Antha declarations or statements. // // If src is a partial source file, the leading and trailing space of src // is applied to the result (such that it has the same leading and trailing // space as src), and the result is indented by the same amount as the first // line of src containing code. Imports are not sorted for partial source files. // func Source(src []byte) ([]byte, error) { fset := token.NewFileSet() node, err := parse(fset, src) if err != nil { return nil, err } var buf bytes.Buffer if file, ok := node.(*ast.File); ok { // Complete source file. ast.SortImports(fset, file) err := config.Fprint(&buf, fset, file) if err != nil { return nil, err } } else { // Partial source file. // Determine and prepend leading space. i, j := 0, 0 for j < len(src) && isSpace(src[j]) { if src[j] == '\n' { i = j + 1 // index of last line in leading space } j++ } buf.Write(src[:i]) // Determine indentation of first code line. // Spaces are ignored unless there are no tabs, // in which case spaces count as one tab. indent := 0 hasSpace := false for _, b := range src[i:j] { switch b { case ' ': hasSpace = true case '\t': indent++ } } if indent == 0 && hasSpace { indent = 1 } // Format the source. cfg := config cfg.Indent = indent err := cfg.Fprint(&buf, fset, node) if err != nil { return nil, err } // Determine and append trailing space. i = len(src) for i > 0 && isSpace(src[i-1]) { i-- } buf.Write(src[i:]) } return buf.Bytes(), nil }