func ExampleFprint() { // Parse source file and extract the AST without comments for // this function, with position information referring to the // file set fset. funcAST, fset := parseFunc("example_test.go", "ExampleFprint") // Print the function body into buffer buf. // The file set is provided to the printer so that it knows // about the original source formatting and can add additional // line breaks where they were present in the source. var buf bytes.Buffer printer.Fprint(&buf, fset, funcAST.Body) // Remove braces {} enclosing the function body, unindent, // and trim leading and trailing white space. s := buf.String() s = s[1 : len(s)-1] s = strings.TrimSpace(strings.Replace(s, "\n\t", "\n", -1)) // Print the cleaned-up body text to stdout. fmt.Println(s) // output: // funcAST, fset := parseFunc("example_test.go", "ExampleFprint") // // var buf bytes.Buffer // printer.Fprint(&buf, fset, funcAST.Body) // // s := buf.String() // s = s[1 : len(s)-1] // s = strings.TrimSpace(strings.Replace(s, "\n\t", "\n", -1)) // // fmt.Println(s) }
func ExampleConvertAST() { fset := token.NewFileSet() a, _ := parser.ParseFile(fset, "example.sgo", ` package example type LinkedList struct { Head int // For SGo: ?*LinkedList Tail *LinkedList } `, parser.ParseComments) info := &types.Info{ Defs: map[*ast.Ident]types.Object{}, Uses: map[*ast.Ident]types.Object{}, } cfg := &types.Config{} cfg.Check("", fset, []*ast.File{a}, info) importer.ConvertAST(a, info, nil) printer.Fprint(os.Stdout, fset, a) // Output: // package example // // type LinkedList struct { // Head int // // For SGo: ?*LinkedList // Tail ?*LinkedList // } }
func (c *converter) convertReturnStmt(v *ast.ReturnStmt) { if v == nil { return } if v.Results.EntangledPos == 1 { // return \ err resultsLen := c.lastFunc.Results().Len() results := make([][]byte, 0, resultsLen) for i := 0; i < resultsLen; i++ { typ := c.lastFunc.Results().At(i).Type() switch underlying := typ.Underlying().(type) { case *types.Pointer, *types.Map, *types.Slice, *types.Signature, *types.Interface, *types.Optional: results = append(results, []byte("nil")) case *types.Struct: typ := c.lastFuncAST.Results.List[i].Type buf := &bytes.Buffer{} printer.Fprint(buf, c.fset, typ) results = append(results, append(buf.Bytes(), '{', '}')) case *types.Basic: info := underlying.Info() switch { case info&types.IsBoolean != 0: results = append(results, []byte("false")) case info&types.IsInteger != 0: results = append(results, []byte("0")) case info&types.IsFloat != 0, info&types.IsComplex != 0: results = append(results, []byte("0.0")) case info&types.IsString != 0: results = append(results, []byte(`""`)) default: results = append(results, []byte("nil")) } default: panic(fmt.Sprintf("unhandled Type %v", typ)) } } text := append(bytes.Join(results, []byte(", ")), []byte(", ")...) c.putChunks(int(v.Results.Pos())-1, c.src[c.lastChunkEnd:int(v.Pos())-c.base-1+len("return ")], text) } for _, v := range v.Results.List { c.convertExpr(v) } if v.Results.EntangledPos > 1 { // return x, y, z \ chunk := ", nil" if c.lastFunc.Results().Entangled().Type() == types.Typ[types.Bool] { chunk = ", true" } c.putChunks(int(v.Results.End())+1, c.src[c.lastChunkEnd:int(v.Results.End())-c.base-1], []byte(chunk)) } }
func nodeFmt(node interface{}, fset *token.FileSet) string { var buf bytes.Buffer printer.Fprint(&buf, fset, node) return strings.Replace(strings.TrimSpace(buf.String()), "\n", "\n\t", -1) }
func fileWithAnnotationComments(file *ast.File, fset, oldFset *token.FileSet, src []byte) ([]byte, *ast.File, error) { // TODO: So this is an extremely hacky way of doing this. We're going to // add the comments directly to the source comments, as text, and then // we're going to re-parse it. This is because I tried manipulating the // AST, adding the commments there an shifting the nodes' positions, but // doing that right is very very convoluted; you need to be tracking all // the time where you are, where you _were_, figure out where's a line // break, etc. So, well, this will do for now. var err error var dstChunks [][]byte var lastChunkEnd int skipNextSpec := false addDoc := func(node ast.Node, name *ast.Ident, typ ast.Expr) { if typ == nil { return } if name != nil && len(name.Name) > 0 { c := name.Name[0] if !(c >= 'A' && c <= 'Z') { return } } buf := &bytes.Buffer{} err = printer.Fprint(buf, token.NewFileSet(), typ) if err != nil { return } pos := int(node.Pos()) - oldFset.File(file.Pos()).Base() var space []byte for i := pos - 1; i >= 0 && (src[i] == ' ' || src[i] == '\t'); i-- { space = append([]byte{src[i]}, space...) } text := append([]byte("// For SGo: "+buf.String()+"\n"), space...) dstChunks = append(dstChunks, src[lastChunkEnd:pos], text) lastChunkEnd = pos } var visitor visitorFunc visitor = visitorFunc(func(node ast.Node) (w ast.Visitor) { var typ ast.Expr var name *ast.Ident switch node := node.(type) { case *ast.FuncDecl: typ = node.Type name = node.Name case *ast.GenDecl: if node.Lparen != 0 || node.Tok == token.IMPORT || node.Tok == token.CONST { return visitor } switch spec := node.Specs[0].(type) { case *ast.TypeSpec: skipNextSpec = true typ = spec.Type name = spec.Name case *ast.ValueSpec: skipNextSpec = true typ = spec.Type if len(spec.Names.List) > 0 { name = spec.Names.List[0] } } switch typ.(type) { case *ast.InterfaceType, *ast.StructType: return visitor } case *ast.InterfaceType: for i := 0; i < len(node.Methods.List); i++ { item := node.Methods.List[i] if len(item.Names) > 0 { name = item.Names[0] } addDoc(item, name, item.Type) } return visitor case *ast.StructType: for i := 0; i < len(node.Fields.List); i++ { item := node.Fields.List[i] if len(item.Names) > 0 { name = item.Names[0] } addDoc(item, name, item.Type) } return visitor case *ast.TypeSpec: if skipNextSpec { skipNextSpec = false return visitor } typ = node.Type name = node.Name case *ast.ValueSpec: if skipNextSpec { skipNextSpec = false return visitor } typ = node.Type if len(node.Names.List) > 0 { name = node.Names.List[0] } default: return visitor } addDoc(node, name, typ) return visitor }) ast.Walk(visitor, file) if err != nil { return nil, nil, err } dst := append( []byte("// Autogenerated by SGo revision: "+SGoRevision+"\n// DO NOT EDIT!\n\n"), bytes.Join(append(dstChunks, src[lastChunkEnd:]), nil)...) dstFile, err := parser.ParseFile(fset, file.Name.Name, dst, parser.ParseComments) return dst, dstFile, err }