github.com/goplus/gox@v1.14.13-0.20240308130321-6ff7f61cfae8/c.go (about) 1 /* 2 Copyright 2022 The GoPlus Authors (goplus.org) 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 package gox 15 16 import ( 17 "go/ast" 18 "go/token" 19 "go/types" 20 "strconv" 21 22 "github.com/goplus/gox/internal" 23 ) 24 25 // ---------------------------------------------------------------------------- 26 27 type VFields interface { // virtual fields 28 FindField(cb *CodeBuilder, t *types.Named, name string, arg *Element, src ast.Node) MemberKind 29 FieldRef(cb *CodeBuilder, t *types.Named, name string, src ast.Node) MemberKind 30 } 31 32 type none = struct{} 33 34 type vFieldsMgr struct { 35 vfts map[*types.Named]VFields 36 pubs map[*types.Named]none 37 } 38 39 func CPubName(name string) string { 40 if r := name[0]; 'a' <= r && r <= 'z' { 41 r -= 'a' - 'A' 42 return string(r) + name[1:] 43 } else if r == '_' { 44 return "X" + name 45 } 46 return name 47 } 48 49 func (p *CodeBuilder) getFieldName(t *types.Named, name string) string { 50 if _, ok := p.pubs[t]; ok { 51 return CPubName(name) 52 } 53 return name 54 } 55 56 func (p *CodeBuilder) refVField(t *types.Named, name string, src ast.Node) MemberKind { 57 if vft, ok := p.vfts[t]; ok { 58 return vft.FieldRef(p, t, name, src) 59 } 60 return MemberInvalid 61 } 62 63 func (p *CodeBuilder) findVField(t *types.Named, name string, arg *Element, src ast.Node) MemberKind { 64 if vft, ok := p.vfts[t]; ok { 65 return vft.FindField(p, t, name, arg, src) 66 } 67 return MemberInvalid 68 } 69 70 func (p *Package) ExportFields(t *types.Named) { 71 if p.cb.pubs == nil { 72 p.cb.pubs = make(map[*types.Named]none) 73 } 74 p.cb.pubs[t] = none{} 75 } 76 77 func (p *Package) SetVFields(t *types.Named, vft VFields) { 78 if p.cb.vfts == nil { 79 p.cb.vfts = make(map[*types.Named]VFields) 80 } 81 p.cb.vfts[t] = vft 82 } 83 84 func (p *Package) VFields(t *types.Named) (vft VFields, ok bool) { 85 vft, ok = p.cb.vfts[t] 86 return 87 } 88 89 // ---------------------------------------------------------------------------- 90 91 type BitField struct { 92 Name string // bit field name 93 FldName string // real field name 94 Off int 95 Bits int 96 Pos token.Pos 97 } 98 99 type BitFields struct { 100 flds []*BitField 101 } 102 103 func NewBitFields(flds []*BitField) *BitFields { 104 return &BitFields{flds: flds} 105 } 106 107 func (p *BitFields) At(i int) *BitField { 108 return p.flds[i] 109 } 110 111 func (p *BitFields) Len() int { 112 return len(p.flds) 113 } 114 115 func (p *BitFields) FindField( 116 cb *CodeBuilder, t *types.Named, name string, arg *Element, src ast.Node) MemberKind { 117 for _, v := range p.flds { 118 if v.Name == name { 119 o := t.Underlying().(*types.Struct) 120 if kind := cb.field(o, v.FldName, "", MemberFlagVal, arg, src); kind != MemberInvalid { 121 tfld := cb.stk.Get(-1).Type.(*types.Basic) 122 if (tfld.Info() & types.IsUnsigned) != 0 { 123 if v.Off != 0 { 124 cb.Val(v.Off).BinaryOp(token.SHR) 125 } 126 cb.Val((1 << v.Bits) - 1).BinaryOp(token.AND) 127 } else { 128 bits := int(std.Sizeof(tfld)<<3) - v.Bits 129 cb.Val(bits - v.Off).BinaryOp(token.SHL).Val(bits).BinaryOp(token.SHR) 130 } 131 return kind 132 } 133 } 134 } 135 return MemberInvalid 136 } 137 138 func (p *bfRefType) assign(cb *CodeBuilder, lhs, rhs *ast.Expr) { 139 // *addr = *addr &^ ((1 << bits) - 1) << off) | ((rhs & (1 << bits) - 1)) << off) 140 tname := cb.pkg.autoName() 141 tvar := ident(tname) 142 addr := &ast.UnaryExpr{Op: token.AND, X: *lhs} 143 stmt := &ast.AssignStmt{Lhs: []ast.Expr{tvar}, Tok: token.DEFINE, Rhs: []ast.Expr{addr}} 144 cb.emitStmt(stmt) 145 mask0 := (1 << p.bits) - 1 146 mask := mask0 << p.off 147 maskLit0 := &ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(mask0)} 148 maskLit := &ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(mask)} 149 valMask := &ast.BinaryExpr{X: &ast.StarExpr{X: tvar}, Op: token.AND_NOT, Y: maskLit} 150 rhsExpr := &ast.BinaryExpr{X: *rhs, Op: token.AND, Y: maskLit0} 151 if p.off != 0 { 152 offLit := &ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(p.off)} 153 rhsExpr = &ast.BinaryExpr{X: rhsExpr, Op: token.SHL, Y: offLit} 154 } 155 *lhs = &ast.StarExpr{X: tvar} 156 *rhs = &ast.BinaryExpr{X: valMask, Op: token.OR, Y: rhsExpr} 157 } 158 159 func (p *BitFields) FieldRef(cb *CodeBuilder, t *types.Named, name string, src ast.Node) MemberKind { 160 for _, v := range p.flds { 161 if v.Name == name { 162 stk := cb.stk 163 o := t.Underlying().(*types.Struct) 164 if cb.fieldRef(stk.Get(-1).Val, o, v.FldName, src) { 165 fld := stk.Get(-1) 166 tfld := fld.Type.(*refType).typ.(*types.Basic) 167 stk.Ret(1, &internal.Elem{ 168 Val: fld.Val, Src: src, 169 Type: &bfRefType{typ: tfld, bits: v.Bits, off: v.Off}, 170 }) 171 return MemberField 172 } 173 } 174 } 175 return MemberInvalid 176 } 177 178 // ---------------------------------------------------------------------------- 179 180 type UnionField struct { 181 Name string 182 Off int 183 Type types.Type 184 Pos token.Pos 185 } 186 187 type UnionFields struct { 188 flds []*UnionField 189 } 190 191 func NewUnionFields(flds []*UnionField) *UnionFields { 192 return &UnionFields{flds: flds} 193 } 194 195 func (p *UnionFields) At(i int) *UnionField { 196 return p.flds[i] 197 } 198 199 func (p *UnionFields) Len() int { 200 return len(p.flds) 201 } 202 203 func (p *UnionFields) getField( 204 cb *CodeBuilder, tfld *types.Named, name string, _ ast.Node, ref bool) MemberKind { 205 for _, v := range p.flds { 206 if v.Name == name { 207 obj := cb.stk.Pop() 208 tobj, isPtr := obj.Type, false 209 if tt, ok := tobj.(*types.Pointer); ok { 210 tobj, isPtr = tt.Elem(), true 211 } 212 cb.Typ(types.NewPointer(v.Type)).Typ(types.Typ[types.UnsafePointer]) 213 if v.Off != 0 { 214 cb.Typ(types.Typ[types.Uintptr]).Typ(types.Typ[types.UnsafePointer]) 215 } 216 cb.stk.Push(obj) 217 if tt, ok := tobj.(*types.Named); ok && tt == tfld { // it's an union type 218 if !isPtr { 219 cb.UnaryOp(token.AND) 220 } 221 } else { // it's a type contains a field with union type 222 cb.MemberRef(tfld.Obj().Name()).UnaryOp(token.AND) 223 } 224 if v.Off != 0 { 225 cb.Call(1).Call(1).Val(v.Off).BinaryOp(token.ADD) // => voidptr => uintptr 226 } 227 cb.Call(1).Call(1) // => voidptr => *type 228 if ref { 229 cb.ElemRef() 230 } else { 231 cb.Elem() 232 } 233 return MemberField 234 } 235 } 236 return MemberInvalid 237 } 238 239 func (p *UnionFields) FindField( 240 cb *CodeBuilder, tfld *types.Named, name string, arg *Element, src ast.Node) MemberKind { 241 return p.getField(cb, tfld, name, src, false) 242 } 243 244 func (p *UnionFields) FieldRef(cb *CodeBuilder, tfld *types.Named, name string, src ast.Node) MemberKind { 245 return p.getField(cb, tfld, name, src, true) 246 } 247 248 // ---------------------------------------------------------------------------- 249 250 // NewCSignature creates prototype of a C function. 251 func NewCSignature(params, results *types.Tuple, variadic bool) *types.Signature { 252 crecv := types.NewParam(token.NoPos, nil, "", types.Typ[types.UntypedNil]) 253 return types.NewSignatureType(crecv, nil, nil, params, results, variadic) 254 } 255 256 // IsCSignature checks a prototype is C function or not. 257 func IsCSignature(sig *types.Signature) bool { 258 recv := sig.Recv() 259 return recv != nil && isCSigRecv(recv) 260 } 261 262 func IsMethodRecv(recv *types.Var) bool { 263 return recv != nil && !isCSigRecv(recv) 264 } 265 266 func isCSigRecv(recv *types.Var) bool { 267 return recv.Type() == types.Typ[types.UntypedNil] 268 } 269 270 // ----------------------------------------------------------------------------