summaryrefslogtreecommitdiff
path: root/src/cmd/cgo/cgo.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/cgo/cgo.go')
-rw-r--r--src/cmd/cgo/cgo.go308
1 files changed, 308 insertions, 0 deletions
diff --git a/src/cmd/cgo/cgo.go b/src/cmd/cgo/cgo.go
new file mode 100644
index 000000000..f174b7854
--- /dev/null
+++ b/src/cmd/cgo/cgo.go
@@ -0,0 +1,308 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Cgo; see gmp.go for an overview.
+
+// TODO(rsc):
+// Emit correct line number annotations.
+// Make 6g understand the annotations.
+package main
+
+import (
+ "bufio";
+ "container/vector";
+ "debug/dwarf";
+ "debug/elf";
+ "flag";
+ "fmt";
+ "go/ast";
+ "go/doc";
+ "go/parser";
+ "go/scanner";
+ "go/token";
+ "io";
+ "os";
+)
+
+// Map of uses of C.xxx. The key is the pointer
+// to the use (a pointer so it can be rewritten)
+// and the value is the context ("call", "expr", "type").
+type cmap map[*ast.Expr] string
+
+var noPos token.Position
+
+func usage() {
+ fmt.Fprint(os.Stderr, "usage: cgo [options] file.cgo\n");
+ flag.PrintDefaults();
+}
+
+func main() {
+ flag.Usage = usage;
+ flag.Parse();
+
+ args := flag.Args();
+ if len(args) != 1 {
+ flag.Usage();
+ }
+ filename := args[0];
+
+ prog, err := parser.ParsePkgFile("", filename, parser.ParseComments);
+ if err != nil {
+ fatal(err);
+ }
+
+ // Find the import "C" line and get any extra C preamble.
+ preamble := "";
+ found := false;
+ for _, d := range prog.Decls {
+ d, ok := d.(*ast.GenDecl);
+ if !ok {
+ continue;
+ }
+ for _, s := range d.Specs {
+ s, ok := s.(*ast.ImportSpec);
+ if !ok {
+ continue;
+ }
+ if len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
+ continue;
+ }
+ found = true;
+ if s.Name != nil {
+ error(s.Path[0].Pos(), `cannot rename import "C"`);
+ }
+ if s.Doc != nil {
+ preamble += doc.CommentText(s.Doc) + "\n";
+ }
+ else if len(d.Specs) == 1 && d.Doc != nil {
+ preamble += doc.CommentText(d.Doc) + "\n";
+ }
+ }
+ }
+ if !found {
+ error(noPos, `cannot find import "C"`);
+ }
+
+ // Accumulate pointers to uses of C.x.
+ m := make(cmap);
+ walk(prog, m, "prog");
+
+ fmt.Print(preamble);
+ for p, context := range m {
+ sel := (*p).(*ast.SelectorExpr);
+ fmt.Printf("%s: %s as %s\n", sel.Pos(), sel.Sel.Value, context);
+ }
+}
+
+func walk(x interface{}, m cmap, context string) {
+ switch n := x.(type) {
+ case *ast.Expr:
+ if sel, ok := (*n).(*ast.SelectorExpr); ok {
+ // For now, assume that the only instance of capital C is
+ // when used as the imported package identifier.
+ // The parser should take care of scoping in the future,
+ // so that we will be able to distinguish a "top-level C"
+ // from a local C.
+ if l, ok := sel.X.(*ast.Ident); ok && l.Value == "C" {
+ m[n] = context;
+ break;
+ }
+ }
+ walk(*n, m, context);
+
+ // everything else just recurs
+ default:
+ error(noPos, "unexpected type %T in walk", x);
+ panic();
+
+ case nil:
+
+ // These are ordered and grouped to match ../../pkg/go/ast/ast.go
+ case *ast.Field:
+ walk(&n.Type, m, "type");
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.Ellipsis:
+ case *ast.BasicLit:
+ case *ast.StringList:
+ case *ast.FuncLit:
+ walk(n.Type, m, "type");
+ walk(n.Body, m, "stmt");
+ case *ast.CompositeLit:
+ walk(&n.Type, m, "type");
+ walk(n.Elts, m, "expr");
+ case *ast.ParenExpr:
+ walk(&n.X, m, context);
+ case *ast.SelectorExpr:
+ walk(&n.X, m, "selector");
+ case *ast.IndexExpr:
+ walk(&n.X, m, "expr");
+ walk(&n.Index, m, "expr");
+ if n.End != nil {
+ walk(&n.End, m, "expr");
+ }
+ case *ast.TypeAssertExpr:
+ walk(&n.X, m, "expr");
+ walk(&n.Type, m, "type");
+ case *ast.CallExpr:
+ walk(&n.Fun, m, "call");
+ walk(n.Args, m, "expr");
+ case *ast.StarExpr:
+ walk(&n.X, m, context);
+ case *ast.UnaryExpr:
+ walk(&n.X, m, "expr");
+ case *ast.BinaryExpr:
+ walk(&n.X, m, "expr");
+ walk(&n.Y, m, "expr");
+ case *ast.KeyValueExpr:
+ walk(&n.Key, m, "expr");
+ walk(&n.Value, m, "expr");
+
+ case *ast.ArrayType:
+ walk(&n.Len, m, "expr");
+ walk(&n.Elt, m, "type");
+ case *ast.StructType:
+ walk(n.Fields, m, "field");
+ case *ast.FuncType:
+ walk(n.Params, m, "field");
+ walk(n.Results, m, "field");
+ case *ast.InterfaceType:
+ walk(n.Methods, m, "field");
+ case *ast.MapType:
+ walk(&n.Key, m, "type");
+ walk(&n.Value, m, "type");
+ case *ast.ChanType:
+ walk(&n.Value, m, "type");
+
+ case *ast.BadStmt:
+ case *ast.DeclStmt:
+ walk(n.Decl, m, "decl");
+ case *ast.EmptyStmt:
+ case *ast.LabeledStmt:
+ walk(n.Stmt, m, "stmt");
+ case *ast.ExprStmt:
+ walk(&n.X, m, "expr");
+ case *ast.IncDecStmt:
+ walk(&n.X, m, "expr");
+ case *ast.AssignStmt:
+ walk(n.Lhs, m, "expr");
+ walk(n.Rhs, m, "expr");
+ case *ast.GoStmt:
+ walk(&n.Call, m, "expr");
+ case *ast.DeferStmt:
+ walk(&n.Call, m, "expr");
+ case *ast.ReturnStmt:
+ walk(n.Results, m, "expr");
+ case *ast.BranchStmt:
+ case *ast.BlockStmt:
+ walk(n.List, m, "stmt");
+ case *ast.IfStmt:
+ walk(n.Init, m, "stmt");
+ walk(&n.Cond, m, "expr");
+ walk(n.Body, m, "stmt");
+ walk(n.Else, m, "stmt");
+ case *ast.CaseClause:
+ walk(n.Values, m, "expr");
+ walk(n.Body, m, "stmt");
+ case *ast.SwitchStmt:
+ walk(n.Init, m, "stmt");
+ walk(&n.Tag, m, "expr");
+ walk(n.Body, m, "stmt");
+ case *ast.TypeCaseClause:
+ walk(n.Types, m, "type");
+ walk(n.Body, m, "stmt");
+ case *ast.TypeSwitchStmt:
+ walk(n.Init, m, "stmt");
+ walk(n.Assign, m, "stmt");
+ walk(n.Body, m, "stmt");
+ case *ast.CommClause:
+ walk(n.Lhs, m, "expr");
+ walk(n.Rhs, m, "expr");
+ walk(n.Body, m, "stmt");
+ case *ast.SelectStmt:
+ walk(n.Body, m, "stmt");
+ case *ast.ForStmt:
+ walk(n.Init, m, "stmt");
+ walk(&n.Cond, m, "expr");
+ walk(n.Post, m, "stmt");
+ walk(n.Body, m, "stmt");
+ case *ast.RangeStmt:
+ walk(&n.Key, m, "expr");
+ walk(&n.Value, m, "expr");
+ walk(&n.X, m, "expr");
+ walk(n.Body, m, "stmt");
+
+ case *ast.ImportSpec:
+ case *ast.ValueSpec:
+ walk(&n.Type, m, "type");
+ walk(n.Values, m, "expr");
+ case *ast.TypeSpec:
+ walk(&n.Type, m, "type");
+
+ case *ast.BadDecl:
+ case *ast.GenDecl:
+ walk(n.Specs, m, "spec");
+ case *ast.FuncDecl:
+ if n.Recv != nil {
+ walk(n.Recv, m, "field");
+ }
+ walk(n.Type, m, "type");
+ walk(n.Body, m, "stmt");
+
+ case *ast.File:
+ walk(n.Decls, m, "decl");
+
+ case *ast.Package:
+ for _, f := range n.Files {
+ walk(f, m, "file");
+ }
+
+ case []ast.Decl:
+ for _, d := range n {
+ walk(d, m, context);
+ }
+ case []ast.Expr:
+ for i := range n {
+ walk(&n[i], m, context);
+ }
+ case []*ast.Field:
+ for _, f := range n {
+ walk(f, m, context);
+ }
+ case []ast.Stmt:
+ for _, s := range n {
+ walk(s, m, context);
+ }
+ case []ast.Spec:
+ for _, s := range n {
+ walk(s, m, context);
+ }
+ }
+}
+
+func fatal(err os.Error) {
+ // If err is a scanner.ErrorList, its String will print just
+ // the first error and then (+n more errors).
+ // Instead, turn it into a new Error that will return
+ // details for all the errors.
+ if list, ok := err.(scanner.ErrorList); ok {
+ for _, e := range list {
+ fmt.Fprintln(os.Stderr, e);
+ }
+ } else {
+ fmt.Fprintln(os.Stderr, err);
+ }
+ os.Exit(2);
+}
+
+var nerrors int
+
+func error(pos token.Position, msg string, args ...) {
+ nerrors++;
+ if pos.IsValid() {
+ fmt.Fprintf(os.Stderr, "%s: ", pos);
+ }
+ fmt.Fprintf(os.Stderr, msg, args);
+ fmt.Fprintf(os.Stderr, "\n");
+}