github.com/gotranspile/cxgo@v0.3.7/pointers.go (about)

     1  package cxgo
     2  
     3  import (
     4  	"go/ast"
     5  	"go/token"
     6  
     7  	"github.com/gotranspile/cxgo/types"
     8  )
     9  
    10  // PtrExpr is an expression that returns a pointer value.
    11  type PtrExpr interface {
    12  	Expr
    13  	// PtrType return an underlying pointer type.
    14  	PtrType(exp types.PtrType) types.PtrType
    15  }
    16  
    17  // ToPointer asserts that a value is a pointer. If it's not, it is converted to a void pointer.
    18  func (g *translator) ToPointer(x Expr) PtrExpr {
    19  	if x, ok := x.(PtrExpr); ok {
    20  		return x
    21  	}
    22  	if x, ok := cUnwrap(x).(IntLit); ok && x.IsZero() {
    23  		return g.Nil()
    24  	}
    25  	xt := x.CType(nil)
    26  	xk := xt.Kind()
    27  	if xk.IsFunc() {
    28  		return &FuncToPtr{
    29  			e: g.env.Env, X: g.ToFunc(x, nil),
    30  		}
    31  	}
    32  	if xk.IsPtr() {
    33  		switch x := x.(type) {
    34  		case Ident:
    35  			return PtrIdent{x.Identifier()}
    36  		}
    37  	}
    38  	if xk.Is(types.Array) {
    39  		// &x[0]
    40  		return g.cAddr(g.NewCIndexExpr(x, cIntLit(0), nil))
    41  	}
    42  	if xk.IsInt() {
    43  		return g.cIntToPtr(x)
    44  	}
    45  	if xk.IsBool() {
    46  		return g.cIntToPtr(&BoolToInt{X: g.ToBool(x)})
    47  	}
    48  	if l, ok := x.(StringLit); ok {
    49  		// string -> *wchar_t
    50  		// string -> *byte
    51  		return g.StringToPtr(l)
    52  	}
    53  	if x.CType(nil).Kind().IsPtr() {
    54  		return PtrAssert{X: x}
    55  	}
    56  	return g.cIntToPtr(x)
    57  }
    58  
    59  var _ PtrExpr = Nil{}
    60  
    61  func NewNil(size int) Nil {
    62  	return Nil{size: size}
    63  }
    64  
    65  func unwrapCasts(e Expr) Expr {
    66  	switch e := e.(type) {
    67  	case *CParentExpr:
    68  		return unwrapCasts(e.Expr)
    69  	case *CCastExpr:
    70  		return unwrapCasts(e.Expr)
    71  	case *StringToPtr:
    72  		return unwrapCasts(e.X)
    73  	}
    74  	return e
    75  }
    76  
    77  func IsNil(e Expr) bool {
    78  	e = unwrapCasts(e)
    79  	if e == nil {
    80  		return false
    81  	}
    82  	switch e := e.(type) {
    83  	case Nil:
    84  		return true
    85  	case IntLit:
    86  		return e.IsZero()
    87  	}
    88  	return false
    89  }
    90  
    91  type Nil struct {
    92  	size int
    93  }
    94  
    95  func (Nil) Visit(v Visitor) {}
    96  
    97  func (e Nil) CType(exp types.Type) types.Type {
    98  	switch t := types.Unwrap(exp).(type) {
    99  	case types.PtrType:
   100  		return e.PtrType(t)
   101  	case *types.FuncType:
   102  		return e.FuncType(t)
   103  	}
   104  	return e.PtrType(nil)
   105  }
   106  
   107  func (Nil) AsExpr() GoExpr {
   108  	return ident("nil")
   109  }
   110  
   111  func (Nil) IsConst() bool {
   112  	return true
   113  }
   114  
   115  func (Nil) HasSideEffects() bool {
   116  	return false
   117  }
   118  
   119  func (e Nil) PtrType(exp types.PtrType) types.PtrType {
   120  	if exp != nil {
   121  		return exp
   122  	}
   123  	return types.NilT(e.size)
   124  }
   125  
   126  func (e Nil) FuncType(exp *types.FuncType) *types.FuncType {
   127  	return exp
   128  }
   129  
   130  func (e Nil) Uses() []types.Usage {
   131  	return nil
   132  }
   133  
   134  var (
   135  	_ PtrExpr = PtrIdent{}
   136  	_ Ident   = PtrIdent{}
   137  )
   138  
   139  type PtrIdent struct {
   140  	*types.Ident
   141  }
   142  
   143  func (PtrIdent) Visit(v Visitor) {}
   144  
   145  func (e PtrIdent) Identifier() *types.Ident {
   146  	return e.Ident
   147  }
   148  
   149  func (e PtrIdent) IsConst() bool {
   150  	return false
   151  }
   152  
   153  func (e PtrIdent) HasSideEffects() bool {
   154  	return false
   155  }
   156  
   157  func (e PtrIdent) AsExpr() GoExpr {
   158  	return e.GoIdent()
   159  }
   160  
   161  func (e PtrIdent) PtrType(exp types.PtrType) types.PtrType {
   162  	var et types.Type
   163  	if exp != nil {
   164  		et = exp
   165  	}
   166  	return types.Unwrap(e.CType(et)).(types.PtrType)
   167  }
   168  
   169  func (e PtrIdent) Uses() []types.Usage {
   170  	return []types.Usage{{Ident: e.Ident, Access: types.AccessUnknown}}
   171  }
   172  
   173  var _ PtrExpr = PtrAssert{}
   174  
   175  type PtrAssert struct {
   176  	X Expr
   177  }
   178  
   179  func (e PtrAssert) Visit(v Visitor) {
   180  	v(e.X)
   181  }
   182  
   183  func (e PtrAssert) CType(types.Type) types.Type {
   184  	return e.X.CType(nil)
   185  }
   186  
   187  func (e PtrAssert) IsConst() bool {
   188  	return e.X.IsConst()
   189  }
   190  
   191  func (e PtrAssert) HasSideEffects() bool {
   192  	return e.X.HasSideEffects()
   193  }
   194  
   195  func (e PtrAssert) AsExpr() GoExpr {
   196  	return e.X.AsExpr()
   197  }
   198  
   199  func (e PtrAssert) PtrType(types.PtrType) types.PtrType {
   200  	return types.Unwrap(e.CType(nil)).(types.PtrType)
   201  }
   202  
   203  func (e PtrAssert) Uses() []types.Usage {
   204  	return e.X.Uses()
   205  }
   206  
   207  var _ PtrExpr = (*TakeAddr)(nil)
   208  
   209  func (g *translator) cAddr(x Expr) PtrExpr {
   210  	if x, ok := cUnwrap(x).(*Deref); ok {
   211  		return x.X
   212  	}
   213  	xt := x.CType(nil)
   214  	if xt.Kind().IsFunc() {
   215  		return g.ToPointer(x)
   216  	}
   217  	if xt.Kind().Is(types.Array) {
   218  		if m, ok := x.(*MakeExpr); ok && m.Size.IsConst() {
   219  			if sz, ok := m.Size.(Number); ok && sz.IsOne() {
   220  				return &NewExpr{
   221  					e:    g.env.Env,
   222  					Elem: m.Elem,
   223  				}
   224  			}
   225  		}
   226  		return g.cAddr(g.NewCIndexExpr(x, cUintLit(0), nil))
   227  	}
   228  	return &TakeAddr{g: g, X: x}
   229  }
   230  
   231  var _ PtrExpr = (*TakeAddr)(nil)
   232  
   233  type TakeAddr struct {
   234  	g *translator
   235  	X Expr
   236  }
   237  
   238  func (e *TakeAddr) Visit(v Visitor) {
   239  	v(e.X)
   240  }
   241  
   242  func (e *TakeAddr) CType(exp types.Type) types.Type {
   243  	return e.PtrType(types.ToPtrType(exp))
   244  }
   245  
   246  func (e *TakeAddr) PtrType(types.PtrType) types.PtrType {
   247  	return e.g.env.PtrT(e.X.CType(nil))
   248  }
   249  
   250  func (e *TakeAddr) AsExpr() GoExpr {
   251  	return addr(e.X.AsExpr())
   252  }
   253  
   254  func (e *TakeAddr) IsConst() bool {
   255  	return false
   256  }
   257  
   258  func (e *TakeAddr) HasSideEffects() bool {
   259  	return e.X.HasSideEffects()
   260  }
   261  
   262  func (e *TakeAddr) Uses() []types.Usage {
   263  	return types.UseRead(e.X)
   264  }
   265  
   266  func (g *translator) cDeref(x PtrExpr) Expr {
   267  	if x, ok := cUnwrap(x).(*TakeAddr); ok {
   268  		return cParenLazy(x.X)
   269  	}
   270  	switch x := cUnwrap(x).(type) {
   271  	case *PtrOffset:
   272  		if x.Ind == 0 {
   273  			ptr := x.X
   274  			if x.Conv != nil {
   275  				ptr = g.ToPointer(g.cCast(*x.Conv, ptr))
   276  			}
   277  			return &Deref{g: g, X: ptr}
   278  		}
   279  	case *FuncToPtr:
   280  		// C has pointers to function, as opposed to Go where function variables are always pointers
   281  		// so we should unwrap the cast and return the function identifier itself
   282  		return x.X
   283  	case *CCastExpr:
   284  		if p, ok := x.Type.(types.PtrType); ok && p.Elem().Kind().IsFunc() {
   285  			panic("TODO")
   286  			//return &TypeAssert{
   287  			//	Type: p.Elem(),
   288  			//	Expr: g.NewCCallExpr(pptrFunc, []Expr{c.Expr}),
   289  			//}
   290  		}
   291  	}
   292  	return &Deref{g: g, X: x}
   293  }
   294  
   295  func (g *translator) cDerefT(x Expr, typ types.Type) Expr {
   296  	return g.cDeref(g.ToPointer(x))
   297  }
   298  
   299  var _ Expr = (*Deref)(nil)
   300  
   301  type Deref struct {
   302  	g *translator
   303  	X PtrExpr
   304  }
   305  
   306  func (e *Deref) Visit(v Visitor) {
   307  	v(e.X)
   308  }
   309  
   310  func (e *Deref) CType(types.Type) types.Type {
   311  	elem := e.X.PtrType(nil).Elem()
   312  	if elem == nil {
   313  		// cannot deref unsafe pointers directly
   314  		elem = e.g.env.Go().Byte()
   315  	}
   316  	return elem
   317  }
   318  
   319  func (e *Deref) AsExpr() GoExpr {
   320  	return deref(e.X.AsExpr())
   321  }
   322  
   323  func (e *Deref) IsConst() bool {
   324  	return false
   325  }
   326  
   327  func (e *Deref) HasSideEffects() bool {
   328  	return e.X.HasSideEffects()
   329  }
   330  
   331  func (e *Deref) Uses() []types.Usage {
   332  	return e.X.Uses()
   333  }
   334  
   335  var _ PtrExpr = (*PtrToPtr)(nil)
   336  
   337  func (g *translator) cPtrToPtr(typ types.Type, x PtrExpr) PtrExpr {
   338  	ptyp := types.UnwrapPtr(typ)
   339  	if ptyp == nil {
   340  		panic("must not be nil")
   341  	}
   342  	if types.Same(typ, x.CType(nil)) {
   343  		return x
   344  	}
   345  	switch x := x.(type) {
   346  	case Nil:
   347  		return x
   348  	case *IntToPtr:
   349  		return &IntToPtr{
   350  			X:  x.X,
   351  			To: ptyp,
   352  		}
   353  	case *PtrOffset:
   354  		return &PtrOffset{
   355  			X:    x.X,
   356  			Ind:  x.Ind,
   357  			Conv: &ptyp,
   358  		}
   359  	case *PtrVarOffset:
   360  		return &PtrVarOffset{
   361  			X:    x.X,
   362  			Mul:  x.Mul,
   363  			Ind:  x.Ind,
   364  			Conv: &ptyp,
   365  		}
   366  	case *PtrToPtr:
   367  		if typ.Kind().IsUnsafePtr() && x.X.PtrType(nil).Kind().IsUnsafePtr() {
   368  			return x.X
   369  		}
   370  	}
   371  	if ptyp.Elem() != nil {
   372  		if s, ok := types.Unwrap(x.PtrType(nil).Elem()).(*types.StructType); ok {
   373  			fields := s.Fields()
   374  			if len(fields) != 0 && types.Same(ptyp.Elem(), fields[0].Type()) {
   375  				return g.cAddr(NewCSelectExpr(x, fields[0].Name))
   376  			}
   377  		}
   378  	}
   379  	return &PtrToPtr{
   380  		X:  x,
   381  		To: ptyp,
   382  	}
   383  }
   384  
   385  type PtrToPtr struct {
   386  	X  PtrExpr
   387  	To types.PtrType
   388  }
   389  
   390  func (e *PtrToPtr) Visit(v Visitor) {
   391  	v(e.X)
   392  }
   393  
   394  func (e *PtrToPtr) CType(types.Type) types.Type {
   395  	return e.To
   396  }
   397  
   398  func (e *PtrToPtr) PtrType(types.PtrType) types.PtrType {
   399  	return e.To
   400  }
   401  
   402  func (e *PtrToPtr) AsExpr() GoExpr {
   403  	var tp GoExpr = e.To.GoType()
   404  	if e.To.Elem() != nil {
   405  		switch et := e.X.CType(e.To).(type) {
   406  		case types.IntType:
   407  			panic("IntToPtr must be used instead")
   408  		case types.PtrType:
   409  			if et.Elem() != nil {
   410  				if _, ok := e.To.(types.Named); !ok {
   411  					tp = paren(tp)
   412  				}
   413  				return call(tp, call(unsafePtr(), e.X.AsExpr()))
   414  			}
   415  		}
   416  		tp = paren(tp)
   417  	}
   418  	return call(tp, e.X.AsExpr())
   419  }
   420  
   421  func (e *PtrToPtr) IsConst() bool {
   422  	return e.X.IsConst()
   423  }
   424  
   425  func (e *PtrToPtr) HasSideEffects() bool {
   426  	return e.X.HasSideEffects()
   427  }
   428  
   429  func (e *PtrToPtr) Uses() []types.Usage {
   430  	// TODO: use type
   431  	return e.X.Uses()
   432  }
   433  
   434  var _ PtrExpr = (*IntToPtr)(nil)
   435  
   436  func (g *translator) cIntToPtr(x Expr) PtrExpr {
   437  	switch x.CType(nil).(type) {
   438  	case types.PtrType:
   439  		panic("PtrToPtr must be used")
   440  	}
   441  	if l, ok := cUnwrap(x).(IntLit); ok && !l.IsUint() {
   442  		x = l.OverflowUint(g.env.PtrSize())
   443  	}
   444  	return &IntToPtr{
   445  		X:  x,
   446  		To: g.env.PtrT(nil),
   447  	}
   448  }
   449  
   450  type IntToPtr struct {
   451  	X  Expr
   452  	To types.PtrType
   453  }
   454  
   455  func (e *IntToPtr) Visit(v Visitor) {
   456  	v(e.X)
   457  }
   458  
   459  func (e *IntToPtr) CType(types.Type) types.Type {
   460  	return e.To
   461  }
   462  
   463  func (e *IntToPtr) PtrType(types.PtrType) types.PtrType {
   464  	return e.To
   465  }
   466  
   467  func (e *IntToPtr) AsExpr() GoExpr {
   468  	tp := e.To.GoType()
   469  	x := e.X.AsExpr()
   470  	x = call(ident("uintptr"), x)
   471  	if e.To.Elem() == nil {
   472  		return call(tp, x)
   473  	}
   474  	switch e.X.CType(nil).(type) {
   475  	case types.PtrType:
   476  		panic("PtrToPtr must be used")
   477  	}
   478  	return call(paren(tp), call(unsafePtr(), x))
   479  }
   480  
   481  func (e *IntToPtr) IsConst() bool {
   482  	return e.X.IsConst()
   483  }
   484  
   485  func (e *IntToPtr) HasSideEffects() bool {
   486  	return e.X.HasSideEffects()
   487  }
   488  
   489  func (e *IntToPtr) Uses() []types.Usage {
   490  	// TODO: use type
   491  	return e.X.Uses()
   492  }
   493  
   494  var _ Expr = (*PtrToInt)(nil)
   495  
   496  func (g *translator) cPtrToInt(typ types.Type, x PtrExpr) Expr {
   497  	if typ == nil {
   498  		typ = g.env.DefUintT()
   499  	}
   500  	return &PtrToInt{
   501  		X:  x,
   502  		To: typ,
   503  	}
   504  }
   505  
   506  type PtrToInt struct {
   507  	X  PtrExpr
   508  	To types.Type
   509  }
   510  
   511  func (e *PtrToInt) Visit(v Visitor) {
   512  	v(e.X)
   513  }
   514  
   515  func (e *PtrToInt) CType(types.Type) types.Type {
   516  	return e.To
   517  }
   518  
   519  func (e *PtrToInt) AsExpr() GoExpr {
   520  	x := e.X.AsExpr()
   521  	// TODO: handle functions
   522  	if !e.X.CType(nil).Kind().IsUnsafePtr() {
   523  		x = call(unsafePtr(), x)
   524  	}
   525  	x = call(ident("uintptr"), x)
   526  	return call(e.CType(nil).GoType(), x)
   527  }
   528  
   529  func (e *PtrToInt) IsConst() bool {
   530  	return e.X.IsConst()
   531  }
   532  
   533  func (e *PtrToInt) HasSideEffects() bool {
   534  	return e.X.HasSideEffects()
   535  }
   536  
   537  func (e *PtrToInt) Uses() []types.Usage {
   538  	// TODO: use type
   539  	return e.X.Uses()
   540  }
   541  
   542  func ComparePtrs(x PtrExpr, op ComparisonOp, y PtrExpr) BoolExpr {
   543  	if op.IsRelational() {
   544  		return &PtrComparison{
   545  			X: x, Op: op, Y: y,
   546  		}
   547  	}
   548  	if !op.IsEquality() {
   549  		panic("must not happen")
   550  	}
   551  	// == and != simplifications
   552  	// always compare with the constant on the right
   553  	if x.IsConst() && !y.IsConst() {
   554  		return ComparePtrs(y, op, x)
   555  	}
   556  	return &PtrComparison{
   557  		X: x, Op: op, Y: y,
   558  	}
   559  }
   560  
   561  var _ BoolExpr = (*PtrComparison)(nil)
   562  
   563  type PtrComparison struct {
   564  	X  PtrExpr
   565  	Op ComparisonOp
   566  	Y  PtrExpr
   567  }
   568  
   569  func (e *PtrComparison) Visit(v Visitor) {
   570  	v(e.X)
   571  	v(e.Y)
   572  }
   573  
   574  func (e *PtrComparison) CType(types.Type) types.Type {
   575  	return types.BoolT()
   576  }
   577  
   578  func (e *PtrComparison) AsExpr() GoExpr {
   579  	x := e.X.AsExpr()
   580  	y := e.Y.AsExpr()
   581  	if e.Op.IsRelational() {
   582  		// compare via uintptr
   583  		if !e.X.CType(nil).Kind().IsUnsafePtr() {
   584  			x = call(unsafePtr(), x)
   585  		}
   586  		if !e.Y.CType(nil).Kind().IsUnsafePtr() {
   587  			y = call(unsafePtr(), y)
   588  		}
   589  		x = call(ident("uintptr"), x)
   590  		y = call(ident("uintptr"), y)
   591  	} else {
   592  		xt := e.X.CType(nil)
   593  		yt := e.Y.CType(nil)
   594  		if IsNil(e.X) || IsNil(e.Y) {
   595  			// compare directly
   596  			if IsNil(e.Y) {
   597  				// TODO: workaround for slice comparison with nil
   598  				if addr, ok := e.X.(*TakeAddr); ok {
   599  					if ind, ok := addr.X.(*CIndexExpr); ok {
   600  						if ind.IndexZero() {
   601  							x = ind.Expr.AsExpr()
   602  						}
   603  					}
   604  				}
   605  			}
   606  		} else if e.X.IsConst() || e.Y.IsConst() {
   607  			// compare as uintptr in case of consts
   608  			if e.X.IsConst() {
   609  				if xc, ok := e.X.(*IntToPtr); ok {
   610  					x = xc.X.AsExpr()
   611  				}
   612  			} else {
   613  				if !xt.Kind().IsUnsafePtr() {
   614  					x = call(unsafePtr(), x)
   615  				}
   616  			}
   617  			x = call(ident("uintptr"), x)
   618  
   619  			if e.Y.IsConst() {
   620  				if yc, ok := e.Y.(*IntToPtr); ok {
   621  					y = yc.X.AsExpr()
   622  				}
   623  			} else {
   624  				if !yt.Kind().IsUnsafePtr() {
   625  					y = call(unsafePtr(), y)
   626  				}
   627  			}
   628  			y = call(ident("uintptr"), y)
   629  		} else {
   630  			if !types.Same(xt, yt) {
   631  				// compare as unsafe pointers
   632  				if !xt.Kind().IsUnsafePtr() {
   633  					x = call(unsafePtr(), x)
   634  				}
   635  				if !yt.Kind().IsUnsafePtr() {
   636  					y = call(unsafePtr(), y)
   637  				}
   638  			}
   639  		}
   640  	}
   641  	return &ast.BinaryExpr{
   642  		X:  x,
   643  		Op: e.Op.GoToken(),
   644  		Y:  y,
   645  	}
   646  }
   647  
   648  func (e *PtrComparison) IsConst() bool {
   649  	if IsNil(e.Y) {
   650  		switch x := e.X.(type) {
   651  		case *StringToPtr:
   652  			return x.X.IsConst()
   653  		}
   654  	}
   655  	return e.X.IsConst() && e.Y.IsConst()
   656  }
   657  
   658  func (e *PtrComparison) HasSideEffects() bool {
   659  	return e.X.HasSideEffects() || e.Y.HasSideEffects()
   660  }
   661  
   662  func (e *PtrComparison) Negate() BoolExpr {
   663  	return ComparePtrs(e.X, e.Op.Negate(), e.Y)
   664  }
   665  
   666  func (e *PtrComparison) Uses() []types.Usage {
   667  	return types.UseRead(e.X, e.Y)
   668  }
   669  
   670  func cPtrOffset(x PtrExpr, ind Expr) PtrExpr {
   671  	elem := x.PtrType(nil).ElemSizeof()
   672  	if elem != 1 {
   673  		return &PtrElemOffset{
   674  			X: x, Ind: ind,
   675  		}
   676  	}
   677  	y := ind
   678  	sub := false
   679  	if u, ok := cUnwrap(y).(*CUnaryExpr); ok && u.Op == UnaryMinus {
   680  		y = u.Expr
   681  		sub = true
   682  	}
   683  	mul := elem
   684  	if sub {
   685  		mul = -mul
   686  	}
   687  	if y, ok := cUnwrap(ind).(IntLit); ok {
   688  		y = y.MulLit(int64(mul))
   689  		return &PtrOffset{
   690  			X: x, Ind: y.Int(),
   691  		}
   692  	}
   693  	// TODO: check the ind for a const multiplier
   694  	return &PtrVarOffset{
   695  		X: x, Mul: mul, Ind: y,
   696  	}
   697  }
   698  
   699  var _ PtrExpr = (*PtrOffset)(nil)
   700  
   701  // PtrOffset acts like a pointer arithmetic with a constant value.
   702  // The index is NOT multiplied by the pointer element size.
   703  // It optionally converts the pointer to Conv type.
   704  type PtrOffset struct {
   705  	X    PtrExpr
   706  	Ind  int64
   707  	Conv *types.PtrType
   708  }
   709  
   710  func (e *PtrOffset) Visit(v Visitor) {
   711  	v(e.X)
   712  }
   713  
   714  func (e *PtrOffset) CType(exp types.Type) types.Type {
   715  	return e.PtrType(types.ToPtrType(exp))
   716  }
   717  
   718  func (e *PtrOffset) toType() types.PtrType {
   719  	if e.Conv == nil {
   720  		return e.X.PtrType(nil)
   721  	}
   722  	return *e.Conv
   723  }
   724  
   725  func (e *PtrOffset) parts() (GoExpr, BinaryOp, GoExpr) {
   726  	x := e.X.AsExpr()
   727  	ind := e.Ind
   728  	op := BinOpAdd
   729  	if ind < 0 {
   730  		ind = -ind
   731  		op = BinOpSub
   732  	}
   733  	y := intLit64(ind)
   734  	if e.X.PtrType(nil).Elem() != nil {
   735  		x = call(unsafePtr(), x)
   736  	}
   737  	return x, op, y
   738  }
   739  
   740  func (e *PtrOffset) AsExpr() GoExpr {
   741  	x, tok, y := e.parts()
   742  	if tok != BinOpAdd {
   743  		y = &ast.UnaryExpr{Op: token.SUB, X: y}
   744  	}
   745  	x = call(ident("unsafe.Add"), x, y)
   746  	//if !VirtualPtrs {
   747  	to := e.toType()
   748  	if to.Elem() == nil {
   749  		return x
   750  	}
   751  	return call(to.GoType(), x)
   752  	//}
   753  	//panic("implement me")
   754  }
   755  
   756  func (e *PtrOffset) IsConst() bool {
   757  	return e.X.IsConst()
   758  }
   759  
   760  func (e *PtrOffset) HasSideEffects() bool {
   761  	return e.X.HasSideEffects()
   762  }
   763  
   764  func (e *PtrOffset) PtrType(exp types.PtrType) types.PtrType {
   765  	if e.Conv != nil {
   766  		return *e.Conv
   767  	}
   768  	return e.X.PtrType(exp)
   769  }
   770  
   771  func (e *PtrOffset) Uses() []types.Usage {
   772  	// TODO: use the type
   773  	return e.X.Uses()
   774  }
   775  
   776  var _ PtrExpr = (*PtrElemOffset)(nil)
   777  
   778  // PtrElemOffset acts like a pointer arithmetic with a variable value.
   779  // The index is always multiplied only by the pointer elements size, as opposed to PtrVarOffset.
   780  // This operation is preferable over PtrVarOffset because the size of C and Go structs may not match.
   781  type PtrElemOffset struct {
   782  	X    PtrExpr
   783  	Ind  Expr
   784  	Conv *types.PtrType
   785  }
   786  
   787  func (e *PtrElemOffset) Visit(v Visitor) {
   788  	v(e.X)
   789  	v(e.Ind)
   790  }
   791  
   792  func (e *PtrElemOffset) CType(exp types.Type) types.Type {
   793  	return e.PtrType(types.ToPtrType(exp))
   794  }
   795  
   796  func (e *PtrElemOffset) AsExpr() GoExpr {
   797  	var to types.PtrType
   798  	if e.Conv == nil {
   799  		to = e.X.PtrType(nil)
   800  	} else {
   801  		to = *e.Conv
   802  	}
   803  	x := e.X.AsExpr()
   804  	ind := e.Ind.AsExpr()
   805  	//if !VirtualPtrs {
   806  	op := BinOpAdd
   807  	if u, ok := cUnwrap(e.Ind).(*CUnaryExpr); ok && u.Op == UnaryMinus {
   808  		op = BinOpSub
   809  		ind = u.Expr.AsExpr()
   810  	} else if l, ok := cUnwrap(e.Ind).(IntLit); ok && !l.IsUint() {
   811  		op = BinOpSub
   812  		ind = l.NegateLit().AsExpr()
   813  	}
   814  	y := ind
   815  	if e.X.PtrType(nil).Elem() != nil {
   816  		x = call(unsafePtr(), x)
   817  	}
   818  	indTyp := e.Ind.CType(nil)
   819  	szof := sizeOf(e.X.PtrType(nil).Elem())
   820  	if e.Ind.IsConst() && indTyp.Kind().IsInt() {
   821  		y = &ast.BinaryExpr{
   822  			X:  szof,
   823  			Op: token.MUL,
   824  			Y:  y,
   825  		}
   826  	} else {
   827  		y = &ast.BinaryExpr{
   828  			X:  szof,
   829  			Op: token.MUL,
   830  			Y:  call(ident("uintptr"), y),
   831  		}
   832  	}
   833  	if op == BinOpSub {
   834  		y = call(ident("int"), y)
   835  		y = &ast.UnaryExpr{Op: token.SUB, X: y}
   836  	}
   837  	x = call(ident("unsafe.Add"), x, y)
   838  	if to.Elem() == nil {
   839  		return x
   840  	}
   841  	return call(to.GoType(), x)
   842  	//}
   843  	//panic("implement me")
   844  }
   845  
   846  func (e *PtrElemOffset) IsConst() bool {
   847  	return e.X.IsConst() && e.Ind.IsConst()
   848  }
   849  
   850  func (e *PtrElemOffset) HasSideEffects() bool {
   851  	return e.X.HasSideEffects() || e.Ind.HasSideEffects()
   852  }
   853  
   854  func (e *PtrElemOffset) PtrType(exp types.PtrType) types.PtrType {
   855  	if e.Conv != nil {
   856  		return *e.Conv
   857  	}
   858  	return e.X.PtrType(exp)
   859  }
   860  
   861  func (e *PtrElemOffset) Uses() []types.Usage {
   862  	// TODO: use the type
   863  	return types.UseRead(e.X, e.Ind)
   864  }
   865  
   866  var _ PtrExpr = (*PtrOffset)(nil)
   867  
   868  // PtrVarOffset acts like a pointer arithmetic with a variable value.
   869  // The index is multiplied only by a Mul, but not the pointer element size.
   870  // It optionally converts the pointer to Conv type.
   871  type PtrVarOffset struct {
   872  	X    PtrExpr
   873  	Mul  int
   874  	Ind  Expr
   875  	Conv *types.PtrType
   876  }
   877  
   878  func (e *PtrVarOffset) Visit(v Visitor) {
   879  	v(e.X)
   880  	v(e.Ind)
   881  }
   882  
   883  func (e *PtrVarOffset) CType(exp types.Type) types.Type {
   884  	return e.PtrType(types.ToPtrType(exp))
   885  }
   886  
   887  func (e *PtrVarOffset) AsExpr() GoExpr {
   888  	var to types.PtrType
   889  	if e.Conv == nil {
   890  		to = e.X.PtrType(nil)
   891  	} else {
   892  		to = *e.Conv
   893  	}
   894  	x := e.X.AsExpr()
   895  	ind := e.Ind.AsExpr()
   896  	//if !VirtualPtrs {
   897  	mul := e.Mul
   898  	op := BinOpAdd
   899  	if mul < 0 {
   900  		mul = -mul
   901  		op = BinOpSub
   902  	}
   903  	y := ind
   904  	if e.X.PtrType(nil).Elem() != nil {
   905  		x = call(unsafePtr(), x)
   906  	}
   907  	if !e.Ind.CType(nil).Kind().IsInt() {
   908  		y = call(ident("uintptr"), y)
   909  	}
   910  	if mul != 1 {
   911  		y = &ast.BinaryExpr{
   912  			X:  intLit(mul),
   913  			Op: token.MUL,
   914  			Y:  y,
   915  		}
   916  	}
   917  	if op == BinOpSub {
   918  		if e.Ind.CType(nil).Kind().IsUnsigned() {
   919  			y = call(ident("int"), y)
   920  		}
   921  		y = &ast.UnaryExpr{Op: token.SUB, X: y}
   922  	}
   923  	x = call(ident("unsafe.Add"), x, y)
   924  	if to.Elem() == nil {
   925  		return x
   926  	}
   927  	return call(to.GoType(), x)
   928  	//}
   929  	//panic("implement me")
   930  }
   931  
   932  func (e *PtrVarOffset) IsConst() bool {
   933  	return e.X.IsConst() && e.Ind.IsConst()
   934  }
   935  
   936  func (e *PtrVarOffset) HasSideEffects() bool {
   937  	return e.X.HasSideEffects() || e.Ind.HasSideEffects()
   938  }
   939  
   940  func (e *PtrVarOffset) PtrType(exp types.PtrType) types.PtrType {
   941  	if e.Conv != nil {
   942  		return *e.Conv
   943  	}
   944  	return e.X.PtrType(exp)
   945  }
   946  
   947  func (e *PtrVarOffset) Uses() []types.Usage {
   948  	// TODO: use the type
   949  	return types.UseRead(e.X, e.Ind)
   950  }
   951  
   952  func cPtrDiff(x, y PtrExpr) Expr {
   953  	return &PtrDiff{X: x, Y: y}
   954  }
   955  
   956  var _ Expr = (*PtrDiff)(nil)
   957  
   958  type PtrDiff struct {
   959  	X PtrExpr
   960  	Y PtrExpr
   961  }
   962  
   963  func (e *PtrDiff) Visit(v Visitor) {
   964  	v(e.X)
   965  	v(e.Y)
   966  }
   967  
   968  func (e *PtrDiff) CType(exp types.Type) types.Type {
   969  	return types.IntT(e.X.PtrType(nil).Sizeof())
   970  }
   971  
   972  func (e *PtrDiff) AsExpr() GoExpr {
   973  	x, y := e.X.AsExpr(), e.Y.AsExpr()
   974  	if e.X.PtrType(nil).Elem() != nil {
   975  		x = call(unsafePtr(), x)
   976  	}
   977  	if e.Y.PtrType(nil).Elem() != nil {
   978  		y = call(unsafePtr(), y)
   979  	}
   980  	return call(e.CType(nil).GoType(), &ast.BinaryExpr{
   981  		X:  call(ident("uintptr"), x),
   982  		Op: token.SUB,
   983  		Y:  call(ident("uintptr"), y),
   984  	})
   985  }
   986  
   987  func (e *PtrDiff) IsConst() bool {
   988  	return false
   989  }
   990  
   991  func (e *PtrDiff) HasSideEffects() bool {
   992  	return e.X.HasSideEffects() || e.Y.HasSideEffects()
   993  }
   994  
   995  func (e *PtrDiff) Uses() []types.Usage {
   996  	return types.UseRead(e.X, e.Y)
   997  }
   998  
   999  var _ PtrExpr = (*StringToPtr)(nil)
  1000  
  1001  func (g *translator) StringToPtr(x StringLit) PtrExpr {
  1002  	return &StringToPtr{e: g.env.Env, X: x}
  1003  }
  1004  
  1005  type StringToPtr struct {
  1006  	e *types.Env
  1007  	X StringLit
  1008  }
  1009  
  1010  func (e *StringToPtr) Visit(v Visitor) {
  1011  	v(e.X)
  1012  }
  1013  
  1014  func (e *StringToPtr) CType(exp types.Type) types.Type {
  1015  	return e.PtrType(types.ToPtrType(exp))
  1016  }
  1017  
  1018  func (e *StringToPtr) AsExpr() GoExpr {
  1019  	if e.X.IsWide() {
  1020  		return call(ident("libc.CWString"), e.X.AsExpr())
  1021  	}
  1022  	return call(ident("libc.CString"), e.X.AsExpr())
  1023  }
  1024  
  1025  func (e *StringToPtr) IsConst() bool {
  1026  	return false
  1027  }
  1028  
  1029  func (e *StringToPtr) HasSideEffects() bool {
  1030  	return false
  1031  }
  1032  
  1033  func (e *StringToPtr) PtrType(types.PtrType) types.PtrType {
  1034  	if e.X.IsWide() {
  1035  		return e.e.C().WString()
  1036  	}
  1037  	return e.e.C().String()
  1038  }
  1039  
  1040  func (e *StringToPtr) Uses() []types.Usage {
  1041  	return e.X.Uses()
  1042  }
  1043  
  1044  var _ PtrExpr = (*NewExpr)(nil)
  1045  
  1046  type NewExpr struct {
  1047  	e    *types.Env
  1048  	Elem types.Type
  1049  }
  1050  
  1051  func (e *NewExpr) Visit(_ Visitor) {
  1052  }
  1053  
  1054  func (e *NewExpr) CType(_ types.Type) types.Type {
  1055  	return e.e.PtrT(e.Elem)
  1056  }
  1057  
  1058  func (e *NewExpr) AsExpr() GoExpr {
  1059  	t := e.Elem.GoType()
  1060  	return call(ident("new"), t)
  1061  }
  1062  
  1063  func (e *NewExpr) IsConst() bool {
  1064  	return false
  1065  }
  1066  
  1067  func (e *NewExpr) HasSideEffects() bool {
  1068  	return true
  1069  }
  1070  
  1071  func (e *NewExpr) Uses() []types.Usage {
  1072  	// TODO: use type
  1073  	return nil
  1074  }
  1075  
  1076  func (e *NewExpr) PtrType(_ types.PtrType) types.PtrType {
  1077  	return e.e.PtrT(e.Elem)
  1078  }
  1079  
  1080  var _ Expr = (*MakeExpr)(nil)
  1081  
  1082  type MakeExpr struct {
  1083  	e    *types.Env
  1084  	Elem types.Type
  1085  	Size Expr
  1086  	Cap  Expr
  1087  }
  1088  
  1089  func (e *MakeExpr) Visit(v Visitor) {
  1090  	v(e.Size)
  1091  	v(e.Cap)
  1092  }
  1093  
  1094  func (e *MakeExpr) CType(_ types.Type) types.Type {
  1095  	return types.SliceT(e.Elem)
  1096  }
  1097  
  1098  func (e *MakeExpr) AsExpr() GoExpr {
  1099  	tp := e.CType(nil).GoType()
  1100  	if e.Cap != nil {
  1101  		return call(ident("make"), tp, e.Size.AsExpr(), e.Cap.AsExpr())
  1102  	}
  1103  	return call(ident("make"), tp, e.Size.AsExpr())
  1104  }
  1105  
  1106  func (e *MakeExpr) IsConst() bool {
  1107  	return false
  1108  }
  1109  
  1110  func (e *MakeExpr) HasSideEffects() bool {
  1111  	return true
  1112  }
  1113  
  1114  func (e *MakeExpr) Uses() []types.Usage {
  1115  	// TODO: use type
  1116  	return types.UseRead(e.Size, e.Cap)
  1117  }