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  // ----------------------------------------------------------------------------