...

Source file src/pkg/cmd/cgo/godefs.go

     1	// Copyright 2011 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package main
     6	
     7	import (
     8		"bytes"
     9		"fmt"
    10		"go/ast"
    11		"go/printer"
    12		"go/token"
    13		"os"
    14		"path/filepath"
    15		"strings"
    16	)
    17	
    18	// godefs returns the output for -godefs mode.
    19	func (p *Package) godefs(f *File, srcfile string) string {
    20		var buf bytes.Buffer
    21	
    22		fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n")
    23		fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[1:], " "))
    24		fmt.Fprintf(&buf, "\n")
    25	
    26		override := make(map[string]string)
    27	
    28		// Allow source file to specify override mappings.
    29		// For example, the socket data structures refer
    30		// to in_addr and in_addr6 structs but we want to be
    31		// able to treat them as byte arrays, so the godefs
    32		// inputs in package syscall say
    33		//
    34		//	// +godefs map struct_in_addr [4]byte
    35		//	// +godefs map struct_in_addr6 [16]byte
    36		//
    37		for _, g := range f.Comments {
    38			for _, c := range g.List {
    39				i := strings.Index(c.Text, "+godefs map")
    40				if i < 0 {
    41					continue
    42				}
    43				s := strings.TrimSpace(c.Text[i+len("+godefs map"):])
    44				i = strings.Index(s, " ")
    45				if i < 0 {
    46					fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text)
    47					continue
    48				}
    49				override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.TrimSpace(s[i:])
    50			}
    51		}
    52		for _, n := range f.Name {
    53			if s := override[n.Go]; s != "" {
    54				override[n.Mangle] = s
    55			}
    56		}
    57	
    58		// Otherwise, if the source file says type T C.whatever,
    59		// use "T" as the mangling of C.whatever,
    60		// except in the definition (handled at end of function).
    61		refName := make(map[*ast.Expr]*Name)
    62		for _, r := range f.Ref {
    63			refName[r.Expr] = r.Name
    64		}
    65		for _, d := range f.AST.Decls {
    66			d, ok := d.(*ast.GenDecl)
    67			if !ok || d.Tok != token.TYPE {
    68				continue
    69			}
    70			for _, s := range d.Specs {
    71				s := s.(*ast.TypeSpec)
    72				n := refName[&s.Type]
    73				if n != nil && n.Mangle != "" {
    74					override[n.Mangle] = s.Name.Name
    75				}
    76			}
    77		}
    78	
    79		// Extend overrides using typedefs:
    80		// If we know that C.xxx should format as T
    81		// and xxx is a typedef for yyy, make C.yyy format as T.
    82		for typ, def := range typedef {
    83			if new := override[typ]; new != "" {
    84				if id, ok := def.Go.(*ast.Ident); ok {
    85					override[id.Name] = new
    86				}
    87			}
    88		}
    89	
    90		// Apply overrides.
    91		for old, new := range override {
    92			if id := goIdent[old]; id != nil {
    93				id.Name = new
    94			}
    95		}
    96	
    97		// Any names still using the _C syntax are not going to compile,
    98		// although in general we don't know whether they all made it
    99		// into the file, so we can't warn here.
   100		//
   101		// The most common case is union types, which begin with
   102		// _Ctype_union and for which typedef[name] is a Go byte
   103		// array of the appropriate size (such as [4]byte).
   104		// Substitute those union types with byte arrays.
   105		for name, id := range goIdent {
   106			if id.Name == name && strings.Contains(name, "_Ctype_union") {
   107				if def := typedef[name]; def != nil {
   108					id.Name = gofmt(def)
   109				}
   110			}
   111		}
   112	
   113		conf.Fprint(&buf, fset, f.AST)
   114	
   115		return buf.String()
   116	}
   117	
   118	var gofmtBuf bytes.Buffer
   119	
   120	// gofmt returns the gofmt-formatted string for an AST node.
   121	func gofmt(n interface{}) string {
   122		gofmtBuf.Reset()
   123		err := printer.Fprint(&gofmtBuf, fset, n)
   124		if err != nil {
   125			return "<" + err.Error() + ">"
   126		}
   127		return gofmtBuf.String()
   128	}
   129	
   130	// gofmtLineReplacer is used to put a gofmt-formatted string for an
   131	// AST expression onto a single line. The lexer normally inserts a
   132	// semicolon at each newline, so we can replace newline with semicolon.
   133	// However, we can't do that in cases where the lexer would not insert
   134	// a semicolon. We only have to worry about cases that can occur in an
   135	// expression passed through gofmt, which means composite literals and
   136	// (due to the printer possibly inserting newlines because of position
   137	// information) operators.
   138	var gofmtLineReplacer = strings.NewReplacer(
   139		// Want to replace \n without ; after everything from
   140		// https://golang.org/ref/spec#Operators_and_punctuation
   141		// EXCEPT ++ -- ) ] }
   142		"++\n", "++;",
   143		"--\n", "--;",
   144	
   145		"+\n", "+ ",
   146		"-\n", "- ",
   147		"*\n", "* ",
   148		"/\n", "/ ",
   149		"%\n", "% ",
   150		"&\n", "& ",
   151		"|\n", "| ",
   152		"^\n", "^ ",
   153		"<\n", "< ",
   154		">\n", "> ",
   155		"=\n", "= ",
   156		"!\n", "! ", // not possible in gofmt today
   157		"(\n", "(",
   158		"[\n", "[", // not possible in gofmt today
   159		"{\n", "{",
   160		",\n", ",",
   161		".\n", ". ",
   162		":\n", ": ", // not possible in gofmt today
   163	
   164		"\n", ";",
   165	)
   166	
   167	// gofmtLine returns the gofmt-formatted string for an AST node,
   168	// ensuring that it is on a single line.
   169	func gofmtLine(n interface{}) string {
   170		return gofmtLineReplacer.Replace(gofmt(n))
   171	}
   172	

View as plain text