func (p *printer) file(src *ast.File) { p.setComment(src.Doc) p.print(src.Pos(), src.Tok, blank) p.expr(src.Name) p.declList(src.Decls) p.print(newline) }
// Merges multiple import blocks and then adds paths func (p *compiler) addAnthaImports(file *ast.File, paths []string) { var specs []ast.Spec var decls []ast.Decl var pos token.Pos // Dummy position to use for generated imports for _, d := range file.Decls { gd, ok := d.(*ast.GenDecl) if pos == token.NoPos { pos = d.Pos() } if !ok || gd.Tok != token.IMPORT { decls = append(decls, d) continue } for _, s := range gd.Specs { specs = append(specs, s) } } for _, p := range paths { specs = append(specs, &ast.ImportSpec{ Path: &ast.BasicLit{ Kind: token.STRING, Value: fmt.Sprintf(`"%s"`, p), ValuePos: pos, }}) } if len(specs) == 0 { if len(decls) != len(file.Decls) { // Clean up empty imports file.Decls = decls } return } //if pos == token.NoPos { // log.Panicf("no declarations in antha file: %s", file.Name) //} merged := &ast.GenDecl{ Tok: token.IMPORT, Lparen: pos, Rparen: pos, Specs: specs, } decls = append([]ast.Decl{merged}, decls...) file.Decls = decls // NB(ddn): tried to sort here, but the following needs proper token.Pos, // which are annoying to generate now. A gofmt on the generated file should // be just as good. //ast.SortImports(token.NewFileSet(), file) }
// output when compiled is always a package // so translate protocol etc into package func (p *compiler) file(src *ast.File) { p.analyze(src) p.transform(src) p.setComment(src.Doc) // Print package name p.print(src.Pos(), token.PACKAGE, blank) p.expr(src.Name) // print (transformed) declarations p.declList(src.Decls) p.print(newline) p.generate() }
// fileExports removes unexported declarations from src in place. // func (r *reader) fileExports(src *ast.File) { j := 0 for _, d := range src.Decls { if r.filterDecl(d) { src.Decls[j] = d j++ } } src.Decls = src.Decls[0:j] }
// Remove antha param declarations since they are fully captured in indexParams() func (p *compiler) removeParamDecls(src *ast.File) { var newd []ast.Decl for _, decl := range src.Decls { toadd := true switch decl.(type) { case *ast.GenDecl: switch decl.(*ast.GenDecl).Tok { case token.PARAMETERS, token.DATA, token.INPUTS, token.OUTPUTS: toadd = false } } if toadd { newd = append(newd, decl) } } src.Decls = newd }
// readFile adds the AST for a source file to the reader. // func (r *reader) readFile(src *ast.File) { // add package documentation if src.Doc != nil { r.readDoc(src.Doc) src.Doc = nil // doc consumed - remove from AST } // add all declarations for _, decl := range src.Decls { switch d := decl.(type) { case *ast.GenDecl: switch d.Tok { case token.IMPORT: // imports are handled individually for _, spec := range d.Specs { if s, ok := spec.(*ast.ImportSpec); ok { if import_, err := strconv.Unquote(s.Path.Value); err == nil { r.imports[import_] = 1 } } } case token.CONST, token.VAR: // constants and variables are always handled as a group r.readValue(d) case token.TYPE: // types are handled individually if len(d.Specs) == 1 && !d.Lparen.IsValid() { // common case: single declaration w/o parentheses // (if a single declaration is parenthesized, // create a new fake declaration below, so that // antha/doc type declarations always appear w/o // parentheses) if s, ok := d.Specs[0].(*ast.TypeSpec); ok { r.readType(d, s) } break } for _, spec := range d.Specs { if s, ok := spec.(*ast.TypeSpec); ok { // use an individual (possibly fake) declaration // for each type; this also ensures that each type // gets to (re-)use the declaration documentation // if there's none associated with the spec itself fake := &ast.GenDecl{ Doc: d.Doc, // don't use the existing TokPos because it // will lead to the wrong selection range for // the fake declaration if there are more // than one type in the group (this affects // src/cmd/anthadoc/anthadoc.go's posLink_urlFunc) TokPos: s.Pos(), Tok: token.TYPE, Specs: []ast.Spec{s}, } r.readType(fake, s) } } } case *ast.FuncDecl: r.readFunc(d) } } // collect MARKER(...): annotations r.readNotes(src.Comments) src.Comments = nil // consumed unassociated comments - remove from AST }