// rewriteTypes rewrites C types appearing in the program to equivalent Go types. func rewriteTypes(cfg *Config, prog cc.Syntax) { // Cache is needed to cut off translation of recursive types. cache := make(map[*cc.Type]*cc.Type) cc.Postorder(prog, func(x cc.Syntax) { if t, ok := x.(*cc.Type); ok { if t.Kind == cc.Struct || t.Kind == cc.Enum { for _, d := range t.Decls { d.OuterType = t } } if t.Kind == cc.Func && len(t.Decls) == 1 && t.Decls[0].Type.Is(cc.Void) { t.Decls = nil } } if d, ok := x.(*cc.Decl); ok { if d.Type != nil && d.Type.Kind == cc.Func { for _, d1 := range d.Type.Decls { d1.CurFn = d } if d.Body != nil { for _, s := range d.Body.Block { if s.Op == cc.StmtDecl { s.Decl.CurFn = d } } } } } }) /* t := g.canon.Def() if cc.Char <= t.Kind && t.Kind <= cc.Enum { // Convert to an appropriately sized number. // Canon is largest rank from C; convert to Go. g.goType = &cc.Type{Kind: c2goKind[t.Kind]} continue } if t.Kind == cc.Ptr || t.Kind == cc.Array { // Default is convert to pointer. // If there are any arrays or any pointer arithmetic, convert to slice instead. k := cc.Ptr for _, d := range g.decls { if d.Type != nil && d.Type.Kind == cc.Array { k = Slice } } for _, f := range g.syntax { if f.ptrAdd { k = Slice } } if t.Base.Kind == cc.Char { g.goType = &cc.Type{Kind: String} continue } g.goType = &cc.Type{Kind: k, Base: toGoType(cfg, nil, nil, t.Base, cache)} continue } */ cc.Postorder(prog, func(x cc.Syntax) { switch x := x.(type) { case *cc.Decl: d := x if d.Name == "..." || d.Type == nil { return } if d.Name == "" && d.Type.Is(cc.Enum) && len(d.Type.Decls) > 0 { for _, dd := range d.Type.Decls { dd.Type = idealType } return } if d.Init != nil && len(d.Init.Braced) > 0 && d.Type != nil && d.Type.Kind == cc.Array { // Initialization of array - do not override type. // But if size is not given explicitly, change to slice. d.Type.Base = toGoType(cfg, nil, d.Type.Base, cache) if d.Type.Width == nil { d.Type.Kind = Slice } return } d.Type = toGoType(cfg, d, d.Type, cache) case *cc.Expr: if x.Type != nil { t := toGoType(cfg, nil, x.Type, cache) if t == nil { fprintf(x.Span, "cannot convert %v to go type\n", GoString(x.Type)) } x.Type = t } } }) }
// rewriteLen rewrites references to length/capacity fields to use len(f) and cap(f) instead. func rewriteLen(cfg *Config, prog *cc.Prog) { cc.Postorder(prog, func(x cc.Syntax) { switch x := x.(type) { case *cc.Expr: // Assign to len, generated by len rewrite. Change to reslice. if x.Op == cc.Eq && x.Left.Op == cc.Call && x.Left.Left.Op == cc.Name && x.Left.Left.Text == "len" && len(x.Left.List) > 0 { arg := x.Left.List[0] x.Left = arg x.Right = &cc.Expr{ Op: ExprSlice, List: []*cc.Expr{arg, nil, x.Right}, } return } if x.Op == cc.Call { // Rewrite call with args x, len(x) to drop len(x). var out []*cc.Expr for _, arg := range x.List { if arg.Op == cc.Call && arg.Left.Op == cc.Name && arg.Left.Text == "len" && len(arg.List) == 1 && len(out) > 0 && arg.List[0].String() == out[len(out)-1].String() { continue } out = append(out, arg) } x.List = out } if (x.Op == cc.Arrow || x.Op == cc.Dot || x.Op == cc.Name) && x.XDecl != nil { k := declKey(x.XDecl) name := cfg.len[k] op := "len" if name == "" { name = cfg.cap[k] op = "cap" if name == "" { return } } var lenExpr *cc.Expr if x.Op == cc.Name { i := strings.Index(name, ".") if i >= 0 { name = name[i+1:] } if goKeyword[name] { name += "_" } else if cfg.rename[name] != "" { name = cfg.rename[name] } lenExpr = &cc.Expr{Op: cc.Name, Text: name} } else { d := x.XDecl if d.OuterType == nil { fmt.Fprintf(os.Stderr, "found use of %s but missing type\n", k) return } t := d.OuterType var other *cc.Decl if i := strings.Index(name, "."); i >= 0 { name = name[i+1:] } for _, dd := range t.Decls { if dd.Name == name { other = dd break } } if other == nil { fmt.Fprintf(os.Stderr, "found use of %s but cannot find field %s\n", k, name) return } left := x.Left lenExpr = &cc.Expr{ Op: cc.Dot, Left: left, Text: name, XDecl: other, } } x.Op = cc.Call x.Left = &cc.Expr{ Op: cc.Name, Text: op, XType: &cc.Type{Kind: cc.Func, Base: intType}, } x.List = []*cc.Expr{lenExpr} } } }) cc.Postorder(prog, func(x cc.Syntax) { switch x := x.(type) { case *cc.Type: out := x.Decls[:0] for _, d := range x.Decls { k := declKey(d) if cfg.len[k] == "" && cfg.cap[k] == "" && !cfg.delete[k] { out = append(out, d) } } x.Decls = out } }) }
// Rewrite from C constructs to Go constructs. func rewriteSyntax(cfg *Config, prog *cc.Prog) { numRewrite++ cc.Preorder(prog, func(x cc.Syntax) { switch x := x.(type) { case *cc.Stmt: rewriteStmt(x) case *cc.Expr: switch x.Op { case cc.Name: switch x.Text { case "nil": x.XDecl = nil // just nil, not main.Nil case "nelem": x.Text = "len" x.XDecl = nil } case cc.Number: // Rewrite char literal. // In general we'd need to rewrite all string and char literals // but these are the only forms that comes up. switch x.Text { case `'\0'`: x.Text = `'\x00'` case `'\"'`: x.Text = `'"'` } case cc.Paren: switch x.Left.Op { case cc.Number, cc.Name: fixMerge(x, x.Left) } case cc.OrEq, cc.AndEq, cc.Or, cc.Eq, cc.EqEq, cc.NotEq, cc.LtEq, cc.GtEq, cc.Lt, cc.Gt: cutParen(x, cc.Or, cc.And, cc.Lsh, cc.Rsh) } case *cc.Type: // Rewrite int f(void) to int f(). if x.Kind == cc.Func && len(x.Decls) == 1 && x.Decls[0].Name == "" && x.Decls[0].Type.Is(cc.Void) { x.Decls = nil } } }) // Apply changed struct tags to typedefs. // Excise dead pieces. cc.Postorder(prog, func(x cc.Syntax) { switch x := x.(type) { case *cc.Type: if x.Kind == cc.TypedefType && x.Base != nil && x.Base.Tag != "" { x.Name = x.Base.Tag } case *cc.Stmt: if x.Op == cc.StmtExpr && x.Expr.Op == cc.Comma && len(x.Expr.List) == 0 { x.Op = cc.Empty } x.Block = filterBlock(x.Block) case *cc.Expr: if x.Op == ExprBlock { x.Block = filterBlock(x.Block) } switch x.Op { case cc.Add, cc.Sub: // Turn p + y - z, which is really (p + y) - z, into p + (y - z), // so that there is only one pointer addition (which will turn into // a slice operation using y-z as the index). if x.XType != nil && x.XType.Kind == cc.Ptr { switch x.Left.Op { case cc.Add, cc.Sub: if x.Left.XType != nil && x.Left.XType.Kind == cc.Ptr { p, op1, y, op2, z := x.Left.Left, x.Left.Op, x.Left.Right, x.Op, x.Right if op1 == cc.Sub { y = &cc.Expr{Op: cc.Minus, Left: y, XType: y.XType} } x.Op = cc.Add x.Left = p x.Right = &cc.Expr{Op: op2, Left: y, Right: z, XType: x.XType} } } } } // Turn c + p - q, which is really (c + p) - q, into c + (p - q), // so that there is no int + ptr addition, only a ptr - ptr subtraction. if x.Op == cc.Sub && x.Left.Op == cc.Add && !isPtrOrArray(x.XType) && isPtrOrArray(x.Left.XType) && !isPtrOrArray(x.Left.Left.XType) { c, p, q := x.Left.Left, x.Left.Right, x.Right expr := x.Left expr.Left = p expr.Right = q expr.Op = cc.Sub x.Op = cc.Add x.Left = c x.Right = expr expr.XType = x.XType } } }) }