cgo: can look up C identifier kind (type or value) and type

gmp.go:197:4:  type mpz_t          C type  mpz_t
gmp.go:205:2:  call mpz_init       C value func(mpz_ptr) void
gmp.go:206:2:  call mpz_set        C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2:  call mpz_init       C value func(mpz_ptr) void
gmp.go:227:7:  call size_t         C type  size_t
gmp.go:228:2:  call mpz_export     C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2:  call mpz_set        C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3:  call mpz_import     C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2:  call mpz_set_si     C value func(mpz_ptr, long int) void
gmp.go:273:5:  call mpz_set_str    C value func(mpz_ptr, *const char, int) int
gmp.go:282:9:  call mpz_get_str    C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3:  call mpz_clear      C value func(mpz_ptr) void
gmp.go:302:2:  call mpz_add        C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2:  call mpz_sub        C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2:  call mpz_mul        C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2:  call mpz_tdiv_q     C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2:  call mpz_tdiv_r     C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2:  call mpz_mul_2exp   C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2:  call mpz_div_2exp   C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3:  call mpz_pow_ui     C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3:  call mpz_powm       C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2:  call mpz_neg        C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2:  call mpz_abs        C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9:  call mpz_cmp        C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2:  call mpz_tdiv_qr    C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2:  call mpz_gcdext     C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void

R=r
DELTA=938  (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
This commit is contained in:
Russ Cox 2009-09-18 11:52:00 -07:00
parent 92f773dc77
commit 6a2602de91
7 changed files with 638 additions and 310 deletions

288
src/cmd/cgo/ast.go Normal file
View file

@ -0,0 +1,288 @@
// 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.
// Parse input AST and prepare Prog structure.
package main
import (
"debug/dwarf";
"fmt";
"go/ast";
"go/doc";
"go/parser";
"go/scanner";
"os";
)
// A Cref refers to an expression of the form C.xxx in the AST.
type Cref struct {
Name string;
Expr *ast.Expr;
Context string; // "type", "expr", or "call"
TypeName bool; // whether xxx is a C type name
DebugType dwarf.Type; // the type of xxx
}
// A Prog collects information about a cgo program.
type Prog struct {
AST *ast.File; // parsed AST
Preamble string; // C preamble (doc comment on import "C")
Crefs []*Cref;
}
func openProg(name string) *Prog {
p := new(Prog);
var err os.Error;
p.AST, err = parser.ParsePkgFile("", name, parser.ParseComments);
if err != nil {
if list, ok := err.(scanner.ErrorList); ok {
// 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.
for _, e := range list {
fmt.Fprintln(os.Stderr, e);
}
os.Exit(2);
}
fatal("parsing %s: %s", name, err);
}
// Find the import "C" line and get any extra C preamble.
found := false;
for _, d := range p.AST.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 {
p.Preamble += doc.CommentText(s.Doc) + "\n";
}
else if len(d.Specs) == 1 && d.Doc != nil {
p.Preamble += doc.CommentText(d.Doc) + "\n";
}
}
}
if !found {
error(noPos, `cannot find import "C"`);
}
// Accumulate pointers to uses of C.x.
p.Crefs = make([]*Cref, 0, 8);
walk(p.AST, p, "prog");
return p;
}
func walk(x interface{}, p *Prog, 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" {
i := len(p.Crefs);
if i >= cap(p.Crefs) {
new := make([]*Cref, 2*i);
for j, v := range p.Crefs {
new[j] = v;
}
p.Crefs = new;
}
p.Crefs = p.Crefs[0:i+1];
p.Crefs[i] = &Cref{
Name: sel.Sel.Value,
Expr: n,
Context: context
};
break;
}
}
walk(*n, p, 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, p, "type");
case *ast.BadExpr:
case *ast.Ident:
case *ast.Ellipsis:
case *ast.BasicLit:
case *ast.StringList:
case *ast.FuncLit:
walk(n.Type, p, "type");
walk(n.Body, p, "stmt");
case *ast.CompositeLit:
walk(&n.Type, p, "type");
walk(n.Elts, p, "expr");
case *ast.ParenExpr:
walk(&n.X, p, context);
case *ast.SelectorExpr:
walk(&n.X, p, "selector");
case *ast.IndexExpr:
walk(&n.X, p, "expr");
walk(&n.Index, p, "expr");
if n.End != nil {
walk(&n.End, p, "expr");
}
case *ast.TypeAssertExpr:
walk(&n.X, p, "expr");
walk(&n.Type, p, "type");
case *ast.CallExpr:
walk(&n.Fun, p, "call");
walk(n.Args, p, "expr");
case *ast.StarExpr:
walk(&n.X, p, context);
case *ast.UnaryExpr:
walk(&n.X, p, "expr");
case *ast.BinaryExpr:
walk(&n.X, p, "expr");
walk(&n.Y, p, "expr");
case *ast.KeyValueExpr:
walk(&n.Key, p, "expr");
walk(&n.Value, p, "expr");
case *ast.ArrayType:
walk(&n.Len, p, "expr");
walk(&n.Elt, p, "type");
case *ast.StructType:
walk(n.Fields, p, "field");
case *ast.FuncType:
walk(n.Params, p, "field");
walk(n.Results, p, "field");
case *ast.InterfaceType:
walk(n.Methods, p, "field");
case *ast.MapType:
walk(&n.Key, p, "type");
walk(&n.Value, p, "type");
case *ast.ChanType:
walk(&n.Value, p, "type");
case *ast.BadStmt:
case *ast.DeclStmt:
walk(n.Decl, p, "decl");
case *ast.EmptyStmt:
case *ast.LabeledStmt:
walk(n.Stmt, p, "stmt");
case *ast.ExprStmt:
walk(&n.X, p, "expr");
case *ast.IncDecStmt:
walk(&n.X, p, "expr");
case *ast.AssignStmt:
walk(n.Lhs, p, "expr");
walk(n.Rhs, p, "expr");
case *ast.GoStmt:
walk(&n.Call, p, "expr");
case *ast.DeferStmt:
walk(&n.Call, p, "expr");
case *ast.ReturnStmt:
walk(n.Results, p, "expr");
case *ast.BranchStmt:
case *ast.BlockStmt:
walk(n.List, p, "stmt");
case *ast.IfStmt:
walk(n.Init, p, "stmt");
walk(&n.Cond, p, "expr");
walk(n.Body, p, "stmt");
walk(n.Else, p, "stmt");
case *ast.CaseClause:
walk(n.Values, p, "expr");
walk(n.Body, p, "stmt");
case *ast.SwitchStmt:
walk(n.Init, p, "stmt");
walk(&n.Tag, p, "expr");
walk(n.Body, p, "stmt");
case *ast.TypeCaseClause:
walk(n.Types, p, "type");
walk(n.Body, p, "stmt");
case *ast.TypeSwitchStmt:
walk(n.Init, p, "stmt");
walk(n.Assign, p, "stmt");
walk(n.Body, p, "stmt");
case *ast.CommClause:
walk(n.Lhs, p, "expr");
walk(n.Rhs, p, "expr");
walk(n.Body, p, "stmt");
case *ast.SelectStmt:
walk(n.Body, p, "stmt");
case *ast.ForStmt:
walk(n.Init, p, "stmt");
walk(&n.Cond, p, "expr");
walk(n.Post, p, "stmt");
walk(n.Body, p, "stmt");
case *ast.RangeStmt:
walk(&n.Key, p, "expr");
walk(&n.Value, p, "expr");
walk(&n.X, p, "expr");
walk(n.Body, p, "stmt");
case *ast.ImportSpec:
case *ast.ValueSpec:
walk(&n.Type, p, "type");
walk(n.Values, p, "expr");
case *ast.TypeSpec:
walk(&n.Type, p, "type");
case *ast.BadDecl:
case *ast.GenDecl:
walk(n.Specs, p, "spec");
case *ast.FuncDecl:
if n.Recv != nil {
walk(n.Recv, p, "field");
}
walk(n.Type, p, "type");
walk(n.Body, p, "stmt");
case *ast.File:
walk(n.Decls, p, "decl");
case *ast.Package:
for _, f := range n.Files {
walk(f, p, "file");
}
case []ast.Decl:
for _, d := range n {
walk(d, p, context);
}
case []ast.Expr:
for i := range n {
walk(&n[i], p, context);
}
case []*ast.Field:
for _, f := range n {
walk(f, p, context);
}
case []ast.Stmt:
for _, s := range n {
walk(s, p, context);
}
case []ast.Spec:
for _, s := range n {
walk(s, p, context);
}
}
}