github.com/gotranspile/cxgo@v0.3.7/c_decl.go (about) 1 package cxgo 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/token" 7 8 "github.com/gotranspile/cxgo/types" 9 ) 10 11 type Range struct { 12 Start int 13 StartLine int 14 End int 15 } 16 17 type CDecl interface { 18 Node 19 AsDecl() []GoDecl 20 Uses() []types.Usage 21 } 22 23 type CVarSpec struct { 24 g *translator 25 Type types.Type 26 Names []*types.Ident 27 Inits []Expr 28 } 29 30 func (d *CVarSpec) Visit(v Visitor) { 31 for _, name := range d.Names { 32 v(IdentExpr{name}) 33 } 34 for _, x := range d.Inits { 35 v(x) 36 } 37 } 38 39 func (d *CVarSpec) GoSpecs(isConst bool) *ast.ValueSpec { 40 var ( 41 names []*ast.Ident 42 init []GoExpr 43 ) 44 var typ GoType 45 if d.Type != nil { 46 typ = d.Type.GoType() 47 } 48 dropType := 0 49 for i, name := range d.Names { 50 if name.Name == "__func__" { 51 continue 52 } 53 names = append(names, name.GoIdent()) 54 if len(d.Inits) != 0 { 55 v := d.Inits[i] 56 if d.Type != nil && v != nil { 57 v = d.g.cCast(d.Type, v) 58 } 59 var e GoExpr 60 if v != nil { 61 e = v.AsExpr() 62 } 63 if ci, ok := e.(*ast.CompositeLit); ok && ci.Type == nil { 64 ci.Type = typ 65 dropType++ 66 } else if _, ok = e.(*ast.BasicLit); ok && isConst { 67 if _, ok := d.Type.(types.Named); !ok || d.g.env.Go().IsBuiltinType(d.Type) { 68 dropType++ 69 } 70 } 71 init = append(init, e) 72 } 73 } 74 if dropType == len(names) { 75 typ = nil 76 } 77 if len(init) != 0 && len(init) < len(names) { 78 panic("partial init") 79 } 80 return &ast.ValueSpec{ 81 Type: typ, 82 Names: names, 83 Values: init, 84 } 85 } 86 87 func (d *CVarSpec) Uses() []types.Usage { 88 var list []types.Usage 89 for i, name := range d.Names { 90 acc := types.AccessDefine 91 if i < len(d.Inits) { 92 acc = types.AccessWrite 93 } 94 list = append(list, types.Usage{Ident: name, Access: acc}) 95 } 96 for _, e := range d.Inits { 97 list = append(list, types.UseRead(e)...) 98 } 99 return list 100 } 101 102 type CVarDecl struct { 103 Const bool 104 Single bool 105 CVarSpec 106 } 107 108 func (d *CVarDecl) Visit(v Visitor) { 109 v(&d.CVarSpec) 110 } 111 112 func (d *CVarDecl) GoField() *GoField { 113 if len(d.Names) > 1 { 114 panic("too large") 115 } 116 if len(d.Inits) != 0 { 117 panic("FIXME") 118 } 119 var names []*ast.Ident 120 if len(d.Names) != 0 { 121 names = append(names, d.Names[0].GoIdent()) 122 } 123 return &GoField{ 124 Names: names, 125 Type: d.Type.GoType(), 126 // FIXME: init 127 } 128 } 129 130 func (d *CVarDecl) AsDecl() []GoDecl { 131 sp := d.GoSpecs(d.Const) 132 if sp == nil || len(sp.Names) == 0 { 133 return nil 134 } 135 single := d.Single 136 tok := token.VAR 137 if d.Const { 138 tok = token.CONST 139 // no complex consts in Go 140 if d.Type != nil && (d.Type.Kind().Is(types.Array) || d.Type.Kind().Is(types.Struct)) { 141 tok = token.VAR 142 } else { 143 for _, v := range d.Inits { 144 if v == nil { 145 single = false 146 continue 147 } 148 if vk := v.CType(nil).Kind(); vk.Is(types.Array) || vk.Is(types.Struct) { 149 tok = token.VAR 150 break 151 } 152 } 153 } 154 } 155 var specs []ast.Spec 156 if single { 157 specs = []ast.Spec{sp} 158 } else { 159 for i, name := range sp.Names { 160 var vals []ast.Expr 161 if len(sp.Values) != 0 && sp.Values[i] != nil { 162 vals = []ast.Expr{sp.Values[i]} 163 } 164 specs = append(specs, &ast.ValueSpec{ 165 Names: []*ast.Ident{name}, 166 Type: sp.Type, 167 Values: vals, 168 }) 169 } 170 } 171 return []GoDecl{&ast.GenDecl{ 172 Tok: tok, 173 Specs: specs, 174 }} 175 } 176 177 type CTypeDef struct { 178 types.Named 179 } 180 181 func (d *CTypeDef) Visit(v Visitor) { 182 v(IdentExpr{d.Name()}) 183 } 184 185 func (d *CTypeDef) AsDecl() []GoDecl { 186 var decls []GoDecl 187 if false && d.Kind().Is(types.Struct) { 188 decls = append(decls, &ast.GenDecl{ 189 Tok: token.VAR, 190 Specs: []ast.Spec{ 191 &ast.ValueSpec{ 192 Names: []*ast.Ident{ident("_")}, 193 Values: []GoExpr{ident(fmt.Sprintf("([1]struct{}{})[%d-unsafe.Sizeof(%s{})]", d.Sizeof(), d.Name().Name))}, 194 }, 195 }, 196 }) 197 } 198 decls = append(decls, &ast.GenDecl{ 199 Tok: token.TYPE, 200 Specs: []ast.Spec{ 201 &ast.TypeSpec{ 202 Name: d.Name().GoIdent(), 203 Type: d.Underlying().GoType(), 204 }, 205 }, 206 }) 207 return decls 208 } 209 210 func (d *CTypeDef) Uses() []types.Usage { 211 // TODO: use type 212 return nil 213 } 214 215 type CFuncDecl struct { 216 Name *types.Ident 217 Type *types.FuncType 218 Body *BlockStmt 219 Range *Range 220 } 221 222 func (d *CFuncDecl) Visit(v Visitor) { 223 v(IdentExpr{d.Name}) 224 v(d.Body) 225 } 226 227 func (d *CFuncDecl) AsDecl() []GoDecl { 228 return []GoDecl{ 229 &ast.FuncDecl{ 230 Name: d.Name.GoIdent(), 231 Type: d.Type.GoFuncType(), 232 Body: d.Body.GoBlockStmt(), 233 }, 234 } 235 } 236 237 func (d *CFuncDecl) Uses() []types.Usage { 238 var list []types.Usage 239 list = append(list, types.Usage{Ident: d.Name, Access: types.AccessDefine}) 240 if d.Body != nil { 241 list = append(list, d.Body.Uses()...) 242 } 243 // TODO: use type 244 return nil 245 }