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

     1  package cxgo
     2  
     3  import (
     4  	"go/ast"
     5  	"go/token"
     6  
     7  	"github.com/gotranspile/cxgo/types"
     8  )
     9  
    10  type Expr interface {
    11  	Node
    12  	// CType returns a type of this expression, given an expected type from the parent.
    13  	// If any type is acceptable, pass nil.
    14  	CType(exp types.Type) types.Type
    15  	AsExpr() GoExpr
    16  	IsConst() bool
    17  	HasSideEffects() bool
    18  	Uses() []types.Usage
    19  }
    20  
    21  func canAssignTo(x Expr) bool {
    22  	x = cUnwrap(x)
    23  	switch x.(type) {
    24  	case Ident, *Deref, *CSelectExpr, *CIndexExpr:
    25  		return true
    26  	}
    27  	return false
    28  }
    29  
    30  type Ident interface {
    31  	Expr
    32  	Identifier() *types.Ident
    33  }
    34  
    35  func cIsTrue(x Expr) bool {
    36  	v, ok := cIsBoolConst(x)
    37  	if ok {
    38  		return v
    39  	}
    40  	return false
    41  }
    42  
    43  type CAsmExpr struct {
    44  	e   *types.Env
    45  	typ types.Type
    46  }
    47  
    48  func (e *CAsmExpr) Visit(_ Visitor) {}
    49  
    50  func (e *CAsmExpr) CType(types.Type) types.Type {
    51  	if e.typ == nil {
    52  		e.typ = e.e.FuncT(
    53  			nil,
    54  			&types.Field{
    55  				Name: types.NewUnnamed(e.e.C().String()),
    56  			},
    57  		)
    58  	}
    59  	return e.typ
    60  }
    61  
    62  func (e *CAsmExpr) IsConst() bool {
    63  	return false
    64  }
    65  
    66  func (e *CAsmExpr) HasSideEffects() bool {
    67  	return true
    68  }
    69  
    70  func (e *CAsmExpr) AsExpr() GoExpr {
    71  	return ident("asm")
    72  }
    73  
    74  func (e *CAsmExpr) Uses() []types.Usage {
    75  	return nil
    76  }
    77  
    78  var _ Expr = &CMultiExpr{}
    79  
    80  func (g *translator) NewCMultiExpr(exprs ...Expr) Expr {
    81  	if len(exprs) == 1 {
    82  		return exprs[0]
    83  	}
    84  	return &CMultiExpr{
    85  		g:     g,
    86  		Exprs: exprs,
    87  	}
    88  }
    89  
    90  // CMultiExpr is a list of C expressions executed one by one, and returning the result of the last one.
    91  type CMultiExpr struct {
    92  	g     *translator
    93  	Exprs []Expr
    94  }
    95  
    96  func (e *CMultiExpr) Visit(v Visitor) {
    97  	for _, x := range e.Exprs {
    98  		v(x)
    99  	}
   100  }
   101  
   102  func (e *CMultiExpr) CType(exp types.Type) types.Type {
   103  	tp := e.Exprs[len(e.Exprs)-1].CType(exp)
   104  	if k := tp.Kind(); k.IsInt() && k.IsUntyped() {
   105  		return e.g.env.DefIntT()
   106  	}
   107  	return tp
   108  }
   109  
   110  func (e *CMultiExpr) IsConst() bool {
   111  	return false
   112  }
   113  
   114  func (e *CMultiExpr) HasSideEffects() bool {
   115  	return true
   116  }
   117  
   118  func (e *CMultiExpr) AsExpr() GoExpr {
   119  	if len(e.Exprs) == 1 {
   120  		return e.Exprs[0].AsExpr()
   121  	}
   122  	typ := e.CType(nil)
   123  	var stmts []CStmt
   124  	for i, x := range e.Exprs {
   125  		if i == len(e.Exprs)-1 {
   126  			stmts = append(stmts, e.g.NewReturnStmt(x, typ)...)
   127  		} else {
   128  			stmts = append(stmts, NewCExprStmt(x)...)
   129  		}
   130  	}
   131  	return callLambda(typ.GoType(), e.g.NewCBlock(stmts...).AsStmt()...)
   132  }
   133  
   134  func (e *CMultiExpr) Uses() []types.Usage {
   135  	var list []types.Usage
   136  	for _, s := range e.Exprs {
   137  		list = append(list, s.Uses()...)
   138  	}
   139  	return list
   140  }
   141  
   142  var (
   143  	_ Expr  = IdentExpr{}
   144  	_ Ident = IdentExpr{}
   145  )
   146  
   147  type IdentExpr struct {
   148  	*types.Ident
   149  }
   150  
   151  func (e IdentExpr) Visit(v Visitor) {}
   152  
   153  func (e IdentExpr) Identifier() *types.Ident {
   154  	return e.Ident
   155  }
   156  
   157  func (e IdentExpr) IsConst() bool {
   158  	return false // TODO: enums
   159  }
   160  
   161  func (e IdentExpr) HasSideEffects() bool {
   162  	return false
   163  }
   164  
   165  func (e IdentExpr) AsExpr() GoExpr {
   166  	return e.GoIdent()
   167  }
   168  
   169  func (e IdentExpr) Uses() []types.Usage {
   170  	return []types.Usage{{Ident: e.Ident, Access: types.AccessUnknown}}
   171  }
   172  
   173  type BinaryOp string
   174  
   175  func (op BinaryOp) Precedence() int {
   176  	switch op {
   177  	case BinOpMult, BinOpDiv, BinOpMod:
   178  		return 4
   179  	case BinOpAdd, BinOpSub:
   180  		return 3
   181  	case BinOpLsh, BinOpRsh:
   182  		return 2
   183  	default:
   184  		return 1
   185  	}
   186  }
   187  
   188  func (op BinaryOp) IsCommutative() bool {
   189  	switch op {
   190  	case BinOpAdd, BinOpMult,
   191  		BinOpBitAnd, BinOpBitOr, BinOpBitXor:
   192  		return true
   193  	}
   194  	return false
   195  }
   196  func (op BinaryOp) IsArithm() bool {
   197  	switch op {
   198  	case BinOpAdd, BinOpSub, BinOpMod, BinOpMult, BinOpDiv:
   199  		return true
   200  	}
   201  	return false
   202  }
   203  func (op BinaryOp) GoToken() token.Token {
   204  	var tok token.Token
   205  	switch op {
   206  	case BinOpMult:
   207  		tok = token.MUL
   208  	case BinOpDiv:
   209  		tok = token.QUO
   210  	case BinOpMod:
   211  		tok = token.REM
   212  	case BinOpAdd:
   213  		tok = token.ADD
   214  	case BinOpSub:
   215  		tok = token.SUB
   216  	case BinOpLsh:
   217  		tok = token.SHL
   218  	case BinOpRsh:
   219  		tok = token.SHR
   220  	case BinOpBitAnd:
   221  		tok = token.AND
   222  	case BinOpBitOr:
   223  		tok = token.OR
   224  	case BinOpBitXor:
   225  		tok = token.XOR
   226  	default:
   227  		panic(op)
   228  	}
   229  	return tok
   230  }
   231  func (op BinaryOp) GoAssignToken() token.Token {
   232  	var tok token.Token
   233  	switch op {
   234  	case "":
   235  		tok = token.ASSIGN
   236  	case BinOpMult:
   237  		tok = token.MUL_ASSIGN
   238  	case BinOpDiv:
   239  		tok = token.QUO_ASSIGN
   240  	case BinOpMod:
   241  		tok = token.REM_ASSIGN
   242  	case BinOpAdd:
   243  		tok = token.ADD_ASSIGN
   244  	case BinOpSub:
   245  		tok = token.SUB_ASSIGN
   246  	case BinOpLsh:
   247  		tok = token.SHL_ASSIGN
   248  	case BinOpRsh:
   249  		tok = token.SHR_ASSIGN
   250  	case BinOpBitAnd:
   251  		tok = token.AND_ASSIGN
   252  	case BinOpBitXor:
   253  		tok = token.XOR_ASSIGN
   254  	case BinOpBitOr:
   255  		tok = token.OR_ASSIGN
   256  	default:
   257  		panic(op)
   258  	}
   259  	return tok
   260  }
   261  
   262  const (
   263  	BinOpMult BinaryOp = "*"
   264  	BinOpDiv  BinaryOp = "/"
   265  	BinOpMod  BinaryOp = "%"
   266  
   267  	BinOpAdd BinaryOp = "+"
   268  	BinOpSub BinaryOp = "-"
   269  
   270  	BinOpLsh BinaryOp = "<<"
   271  	BinOpRsh BinaryOp = ">>"
   272  
   273  	BinOpBitAnd BinaryOp = "&"
   274  	BinOpBitOr  BinaryOp = "|"
   275  	BinOpBitXor BinaryOp = "^"
   276  )
   277  
   278  func (g *translator) NewCBinaryExpr(x Expr, op BinaryOp, y Expr) Expr {
   279  	return g.newCBinaryExpr(nil, x, op, y)
   280  }
   281  func (g *translator) newCBinaryExpr(exp types.Type, x Expr, op BinaryOp, y Expr) Expr {
   282  	if op.IsCommutative() {
   283  		if x.IsConst() && !y.IsConst() {
   284  			// let const to be the second operand
   285  			x, y = y, x
   286  		}
   287  		if x.CType(nil).Kind().IsInt() && y.CType(nil).Kind().IsPtr() {
   288  			x, y = y, x
   289  		}
   290  	}
   291  	if xt := x.CType(nil); xt.Kind().Is(types.Array) {
   292  		at := xt.(types.ArrayType)
   293  		if op == BinOpAdd {
   294  			// index array/slices instead of adding addresses
   295  			return g.cAddr(g.NewCIndexExpr(x, y, nil))
   296  		}
   297  		return g.newCBinaryExpr(exp, g.cCast(g.env.PtrT(at.Elem()), x), op, y)
   298  	}
   299  	if xt := x.CType(nil); xt.Kind().Is(types.Func) && !y.IsConst() {
   300  		return g.newCBinaryExpr(exp, g.cCast(g.env.PtrT(nil), x), op, y)
   301  	}
   302  	if xt, ok := types.Unwrap(x.CType(nil)).(types.PtrType); ok && op.IsArithm() {
   303  		if addr, ok := cUnwrap(x).(*TakeAddr); ok && op == BinOpAdd {
   304  			if ind, ok := addr.X.(*CIndexExpr); ok {
   305  				// adding another component to an existing index expression
   306  				return g.cAddr(g.NewCIndexExpr(ind.Expr,
   307  					g.NewCBinaryExpr(ind.Index, op, y),
   308  					nil))
   309  			}
   310  		}
   311  		x := g.ToPointer(x)
   312  		if yk := y.CType(nil).Kind(); yk.IsInt() {
   313  			if op == BinOpAdd {
   314  				return cPtrOffset(x, y)
   315  			} else if op == BinOpSub {
   316  				return cPtrOffset(x, g.NewCUnaryExpr(UnaryMinus, y))
   317  			}
   318  		} else if yk.IsPtr() {
   319  			if op == BinOpSub {
   320  				return cPtrDiff(x, g.ToPointer(y))
   321  			}
   322  		}
   323  		inc := xt.ElemSizeof()
   324  		if inc != 1 {
   325  			y = g.newCBinaryExpr(exp, y, BinOpMult, cIntLit(int64(inc)))
   326  		}
   327  		return &CBinaryExpr{
   328  			Left:  x,
   329  			Op:    op,
   330  			Right: y,
   331  		}
   332  	}
   333  	typ := g.env.CommonType(x.CType(exp), y.CType(exp))
   334  	x = g.cCast(typ, x)
   335  	y = g.cCast(typ, y)
   336  	return g.cCast(typ, &CBinaryExpr{
   337  		Left:  cParenLazyOp(x, op),
   338  		Op:    op,
   339  		Right: cParenLazyOpR(y, op),
   340  	})
   341  }
   342  
   343  func (g *translator) NewCBinaryExprT(x Expr, op BinaryOp, y Expr, _ types.Type) Expr {
   344  	return g.NewCBinaryExpr(x, op, y)
   345  }
   346  
   347  type CBinaryExpr struct {
   348  	Left  Expr
   349  	Op    BinaryOp
   350  	Right Expr
   351  }
   352  
   353  func (e *CBinaryExpr) Visit(v Visitor) {
   354  	v(e.Left)
   355  	v(e.Right)
   356  }
   357  
   358  func (e *CBinaryExpr) CType(exp types.Type) types.Type {
   359  	l, r := e.Left.CType(nil), e.Right.CType(nil)
   360  	if l.Kind().IsUntyped() {
   361  		return r
   362  	}
   363  	return l
   364  }
   365  
   366  func (e *CBinaryExpr) IsConst() bool {
   367  	return e.Left.IsConst() && e.Right.IsConst()
   368  }
   369  
   370  func (e *CBinaryExpr) HasSideEffects() bool {
   371  	return e.Left.HasSideEffects() || e.Right.HasSideEffects()
   372  }
   373  
   374  func (e *CBinaryExpr) AsExpr() GoExpr {
   375  	return &ast.BinaryExpr{
   376  		X:  e.Left.AsExpr(),
   377  		Op: e.Op.GoToken(),
   378  		Y:  e.Right.AsExpr(),
   379  	}
   380  }
   381  
   382  func (e *CBinaryExpr) Uses() []types.Usage {
   383  	return types.UseRead(e.Left, e.Right)
   384  }
   385  
   386  var (
   387  	_ Expr      = &CTernaryExpr{}
   388  	_ CStmtConv = &CTernaryExpr{}
   389  )
   390  
   391  func (g *translator) NewCTernaryExpr(cond BoolExpr, then, els Expr) Expr {
   392  	return &CTernaryExpr{
   393  		g:    g,
   394  		Cond: cond,
   395  		Then: then,
   396  		Else: els,
   397  	}
   398  }
   399  
   400  type CTernaryExpr struct {
   401  	g    *translator
   402  	Cond BoolExpr
   403  	Then Expr
   404  	Else Expr
   405  }
   406  
   407  func (e *CTernaryExpr) Visit(v Visitor) {
   408  	v(e.Cond)
   409  	v(e.Then)
   410  	v(e.Else)
   411  }
   412  
   413  func (e *CTernaryExpr) CType(types.Type) types.Type {
   414  	tt := e.Then.CType(nil)
   415  	et := e.Else.CType(nil)
   416  	tk := tt.Kind()
   417  	ek := et.Kind()
   418  	if tk.IsInt() && tk.IsUntyped() && ek.IsUntyped() {
   419  		return e.g.env.CommonType(tt, et)
   420  	}
   421  	if tk.IsUntyped() {
   422  		return et
   423  	}
   424  	if tk.Is(types.Array) && et.Kind().IsPtr() {
   425  		return et
   426  	}
   427  	if _, ok := types.Unwrap(tt).(types.IntType); ok {
   428  		if _, ok := types.Unwrap(et).(types.IntType); ok {
   429  			return e.g.env.CommonType(tt, et)
   430  		}
   431  	}
   432  	return tt
   433  }
   434  
   435  func (e *CTernaryExpr) HasSideEffects() bool {
   436  	return e.Cond.HasSideEffects() ||
   437  		e.Then.HasSideEffects() ||
   438  		e.Else.HasSideEffects()
   439  }
   440  
   441  func (e *CTernaryExpr) IsConst() bool {
   442  	return false
   443  }
   444  
   445  func (e *CTernaryExpr) AsExpr() GoExpr {
   446  	ret := e.CType(nil)
   447  	var stmts []GoStmt
   448  	stmts = append(stmts, ifelse(
   449  		e.Cond.AsExpr(),
   450  		asStmts(e.g.NewReturnStmt(e.Then, ret)),
   451  		nil,
   452  	))
   453  	stmts = append(stmts, asStmts(e.g.NewReturnStmt(e.Else, ret))...)
   454  	return callLambda(
   455  		ret.GoType(),
   456  		stmts...,
   457  	)
   458  }
   459  
   460  func (e *CTernaryExpr) ToStmt() []CStmt {
   461  	return []CStmt{e.g.NewCIfStmt(
   462  		e.Cond,
   463  		NewCExprStmt(e.Then),
   464  		e.g.NewCBlock(NewCExprStmt(e.Else)...),
   465  	)}
   466  }
   467  
   468  func (e *CTernaryExpr) Uses() []types.Usage {
   469  	var list []types.Usage
   470  	list = append(list, types.UseRead(e.Cond)...)
   471  	list = append(list, types.UseWrite(e.Then, e.Else)...)
   472  	return list
   473  }
   474  
   475  func cUnwrap(e Expr) Expr {
   476  	switch e := e.(type) {
   477  	case *CParentExpr:
   478  		return cUnwrap(e.Expr)
   479  	case PtrAssert:
   480  		return cUnwrap(e.X)
   481  	case Ident:
   482  		return IdentExpr{e.Identifier()}
   483  	}
   484  	return e
   485  }
   486  
   487  func cUnwrapConst(e Expr) Expr {
   488  	switch e := e.(type) {
   489  	case *CParentExpr:
   490  		return e.Expr
   491  	case *CCastExpr:
   492  		return e.Expr
   493  	}
   494  	return e
   495  }
   496  
   497  func cParenLazyOp(x Expr, pop BinaryOp) Expr {
   498  	if x, ok := x.(*CBinaryExpr); ok {
   499  		if pop.Precedence() <= x.Op.Precedence() {
   500  			return x
   501  		} else if pop.Precedence() > x.Op.Precedence() {
   502  			return cParen(x)
   503  		}
   504  	}
   505  	return cParenLazy(x)
   506  }
   507  
   508  func cParenLazyOpR(x Expr, pop BinaryOp) Expr {
   509  	if x, ok := cUnwrap(x).(*CBinaryExpr); ok {
   510  		if pop.Precedence() < x.Op.Precedence() {
   511  			return x
   512  		} else if pop.Precedence() > x.Op.Precedence() {
   513  			return cParen(x)
   514  		}
   515  	}
   516  	return cParenLazyR(x)
   517  }
   518  
   519  func cParenLazy(x Expr) Expr {
   520  	switch x := x.(type) {
   521  	case *CBinaryExpr, *CAssignExpr, *CTernaryExpr:
   522  		return cParen(x)
   523  	case *CCastExpr:
   524  		switch x.CType(nil).(type) {
   525  		case types.Named, types.IntType, types.FloatType:
   526  			// nop
   527  		default:
   528  			return cParen(x)
   529  		}
   530  	}
   531  	return x
   532  }
   533  
   534  func cParenLazyR(x Expr) Expr {
   535  	switch x := x.(type) {
   536  	case *CUnaryExpr:
   537  		if x.Op == UnaryMinus {
   538  			return cParen(x)
   539  		}
   540  	case IntLit:
   541  		if x.IsNeg() {
   542  			return cParen(x)
   543  		}
   544  	}
   545  	return cParenLazy(x)
   546  }
   547  
   548  func cParen(x Expr) Expr {
   549  	switch x := x.(type) {
   550  	case IdentExpr:
   551  		return x
   552  	case PtrIdent:
   553  		return x
   554  	case FuncIdent:
   555  		return x
   556  	case IntLit:
   557  		if !x.IsNeg() {
   558  			return x
   559  		}
   560  	case FloatLit:
   561  		return x
   562  	case *CLiteral:
   563  		return x
   564  	case *CParentExpr:
   565  		return x
   566  	case *CCompLitExpr:
   567  		return x
   568  	case *CallExpr:
   569  		return x
   570  	case *CSelectExpr:
   571  		return x
   572  	case *CUnaryExpr:
   573  		if p, ok := x.Expr.(*CParentExpr); ok {
   574  			x.Expr = p.Expr
   575  		}
   576  	}
   577  	return &CParentExpr{Expr: x}
   578  }
   579  
   580  type CParentExpr struct {
   581  	Expr Expr
   582  }
   583  
   584  func (e *CParentExpr) Visit(v Visitor) {
   585  	v(e.Expr)
   586  }
   587  
   588  func (e *CParentExpr) CType(types.Type) types.Type {
   589  	return e.Expr.CType(nil)
   590  }
   591  
   592  func (e *CParentExpr) IsConst() bool {
   593  	return e.Expr.IsConst()
   594  }
   595  
   596  func (e *CParentExpr) HasSideEffects() bool {
   597  	return e.Expr.HasSideEffects()
   598  }
   599  
   600  func (e *CParentExpr) AsExpr() GoExpr {
   601  	return paren(e.Expr.AsExpr())
   602  }
   603  
   604  func (e *CParentExpr) Uses() []types.Usage {
   605  	return e.Expr.Uses()
   606  }
   607  
   608  func (g *translator) NewCIndexExpr(x, ind Expr, typ types.Type) Expr {
   609  	ind = cUnwrap(ind)
   610  	if types.Same(x.CType(nil), g.env.Go().String()) {
   611  		return &CIndexExpr{
   612  			ctype: g.env.Go().Byte(),
   613  			Expr:  x,
   614  			Index: ind,
   615  		}
   616  	}
   617  	if addr, ok := cUnwrap(x).(*TakeAddr); ok {
   618  		if ind2, ok := addr.X.(*CIndexExpr); ok {
   619  			// add another component to the index expr
   620  			return g.NewCIndexExpr(ind2.Expr,
   621  				g.NewCBinaryExpr(ind2.Index, BinOpAdd, ind),
   622  				typ)
   623  		}
   624  	}
   625  	if types.IsPtr(x.CType(nil)) {
   626  		x := g.ToPointer(x)
   627  		return g.cDeref(cPtrOffset(x, ind))
   628  	}
   629  	if arr, ok := types.Unwrap(x.CType(nil)).(types.ArrayType); ok {
   630  		typ = arr.Elem()
   631  	} else if typ == nil {
   632  		panic("no type for an element")
   633  	}
   634  	return &CIndexExpr{
   635  		ctype: typ,
   636  		Expr:  x,
   637  		Index: ind,
   638  	}
   639  }
   640  
   641  type CIndexExpr struct {
   642  	ctype types.Type
   643  	Expr  Expr
   644  	Index Expr
   645  }
   646  
   647  func (e *CIndexExpr) IndexZero() bool {
   648  	l, ok := unwrapCasts(e.Index).(IntLit)
   649  	if !ok {
   650  		return false
   651  	}
   652  	return l.IsZero()
   653  }
   654  
   655  func (e *CIndexExpr) Visit(v Visitor) {
   656  	v(e.Expr)
   657  	v(e.Index)
   658  }
   659  
   660  func (e *CIndexExpr) CType(types.Type) types.Type {
   661  	return e.ctype
   662  }
   663  
   664  func (e *CIndexExpr) IsConst() bool {
   665  	return false
   666  }
   667  
   668  func (e *CIndexExpr) HasSideEffects() bool {
   669  	return e.Expr.HasSideEffects() || e.Index.HasSideEffects()
   670  }
   671  
   672  func (e *CIndexExpr) AsExpr() GoExpr {
   673  	return &ast.IndexExpr{
   674  		X:     e.Expr.AsExpr(),
   675  		Index: e.Index.AsExpr(),
   676  	}
   677  }
   678  
   679  func (e *CIndexExpr) Uses() []types.Usage {
   680  	var list []types.Usage
   681  	list = append(list, e.Expr.Uses()...)
   682  	list = append(list, types.UseRead(e.Index)...)
   683  	return list
   684  }
   685  
   686  func NewCSelectExpr(x Expr, f *types.Ident) Expr {
   687  	x2 := cUnwrap(x)
   688  	switch x2 := x2.(type) {
   689  	case Ident:
   690  		x = x2
   691  	case *TakeAddr:
   692  		x = x2.X
   693  	}
   694  	return &CSelectExpr{
   695  		Expr: x, Sel: f,
   696  	}
   697  }
   698  
   699  type CSelectExpr struct {
   700  	Expr Expr
   701  	Sel  *types.Ident
   702  }
   703  
   704  func (e *CSelectExpr) Visit(v Visitor) {
   705  	v(e.Expr)
   706  	v(IdentExpr{e.Sel})
   707  }
   708  
   709  func (e *CSelectExpr) CType(exp types.Type) types.Type {
   710  	return e.Sel.CType(exp)
   711  }
   712  
   713  func (e *CSelectExpr) IsConst() bool {
   714  	return false
   715  }
   716  
   717  func (e *CSelectExpr) HasSideEffects() bool {
   718  	return e.Expr.HasSideEffects()
   719  }
   720  
   721  func (e *CSelectExpr) AsExpr() GoExpr {
   722  	return &ast.SelectorExpr{
   723  		X:   e.Expr.AsExpr(),
   724  		Sel: e.Sel.GoIdent(),
   725  	}
   726  }
   727  
   728  func (e *CSelectExpr) Uses() []types.Usage {
   729  	var list []types.Usage
   730  	list = append(list, types.Usage{Ident: e.Sel, Access: types.AccessUnknown})
   731  	list = append(list, types.UseRead(e.Expr)...)
   732  	return list
   733  }
   734  
   735  var (
   736  	_ CStmtConv = &CIncrExpr{}
   737  )
   738  
   739  func (g *translator) NewCPrefixExpr(x Expr, decr bool) *CIncrExpr {
   740  	return &CIncrExpr{
   741  		g:    g,
   742  		Expr: x, Prefix: true,
   743  		Decr: decr,
   744  	}
   745  }
   746  
   747  func (g *translator) NewCPostfixExpr(x Expr, decr bool) *CIncrExpr {
   748  	return &CIncrExpr{
   749  		g:    g,
   750  		Expr: x, Prefix: false,
   751  		Decr: decr,
   752  	}
   753  }
   754  
   755  type CIncrExpr struct {
   756  	g      *translator
   757  	Expr   Expr
   758  	Prefix bool
   759  	Decr   bool
   760  }
   761  
   762  func (e *CIncrExpr) Visit(v Visitor) {
   763  	v(e.Expr)
   764  }
   765  
   766  func (e *CIncrExpr) CType(types.Type) types.Type {
   767  	return e.Expr.CType(nil)
   768  }
   769  
   770  func (e *CIncrExpr) IsConst() bool {
   771  	return false
   772  }
   773  
   774  func (e *CIncrExpr) HasSideEffects() bool {
   775  	return true
   776  }
   777  
   778  func (e *CIncrExpr) ToStmt() []CStmt {
   779  	return []CStmt{e.g.NewCIncStmt(e.Expr, e.Decr)}
   780  }
   781  
   782  func (e *CIncrExpr) AsExpr() GoExpr {
   783  	pi := types.NewIdent("p", e.g.env.PtrT(e.Expr.CType(nil)))
   784  	p := pi.GoIdent()
   785  	y := e.g.cAddr(e.Expr).AsExpr()
   786  	stmts := []GoStmt{
   787  		define(p, y),
   788  	}
   789  	inc := (&CIncrStmt{
   790  		g:    e.g,
   791  		Expr: e.g.cDeref(PtrIdent{pi}),
   792  		Decr: e.Decr,
   793  	}).AsStmt()
   794  	if e.Prefix {
   795  		stmts = append(stmts, inc...)
   796  		stmts = append(stmts,
   797  			returnStmt(deref(p)),
   798  		)
   799  	} else {
   800  		x := ident("x")
   801  		stmts = append(stmts,
   802  			define(x, deref(p)),
   803  		)
   804  		stmts = append(stmts, inc...)
   805  		stmts = append(stmts,
   806  			returnStmt(x),
   807  		)
   808  	}
   809  	return callLambda(
   810  		e.CType(nil).GoType(),
   811  		stmts...,
   812  	)
   813  }
   814  
   815  func (e *CIncrExpr) Uses() []types.Usage {
   816  	var list []types.Usage
   817  	list = append(list, types.UseRead(e.Expr)...)
   818  	list = append(list, types.UseWrite(e.Expr)...)
   819  	return list
   820  }
   821  
   822  type CCastExpr struct {
   823  	Assert bool
   824  	Expr   Expr
   825  	Type   types.Type
   826  }
   827  
   828  func (e *CCastExpr) Visit(v Visitor) {
   829  	v(e.Expr)
   830  }
   831  
   832  func (e *CCastExpr) CType(_ types.Type) types.Type {
   833  	return e.Type
   834  }
   835  
   836  func (e *CCastExpr) IsConst() bool {
   837  	return e.Expr.IsConst()
   838  }
   839  
   840  func (e *CCastExpr) HasSideEffects() bool {
   841  	return e.Expr.HasSideEffects()
   842  }
   843  
   844  func isParenSafe(v ast.Node) bool {
   845  	switch v := v.(type) {
   846  	case *ast.Ident:
   847  		return true
   848  	case *ast.ArrayType:
   849  		return isParenSafe(v.Elt)
   850  	default:
   851  		return false
   852  	}
   853  }
   854  
   855  func (e *CCastExpr) AsExpr() GoExpr {
   856  	tp := e.Type.GoType()
   857  	if e.Assert {
   858  		return typAssert(e.Expr.AsExpr(), tp)
   859  	}
   860  	switch to := e.Type.(type) {
   861  	case types.PtrType:
   862  		if to.Elem() != nil {
   863  			switch et := e.Expr.CType(nil).(type) {
   864  			case types.IntType:
   865  				return call(paren(tp), call(unsafePtr(), call(ident("uintptr"), e.Expr.AsExpr())))
   866  			case types.PtrType:
   867  				if et.Elem() != nil {
   868  					return call(paren(tp), call(unsafePtr(), e.Expr.AsExpr()))
   869  				}
   870  			}
   871  		}
   872  	}
   873  	if !isParenSafe(tp) {
   874  		tp = paren(tp)
   875  	}
   876  	return call(tp, e.Expr.AsExpr())
   877  }
   878  
   879  func (e *CCastExpr) Uses() []types.Usage {
   880  	return types.UseRead(e.Expr)
   881  }
   882  
   883  type UnaryOp string
   884  
   885  const (
   886  	UnarySizeof UnaryOp = "sizeof"
   887  
   888  	UnaryPlus  UnaryOp = "+"
   889  	UnaryMinus UnaryOp = "-"
   890  	UnaryXor   UnaryOp = "^"
   891  )
   892  
   893  func (g *translator) cSizeofE(x Expr) Expr {
   894  	switch t := types.Unwrap(x.CType(nil)).(type) {
   895  	case types.ArrayType:
   896  		if t.Len() <= 0 {
   897  			return g.newUnaryExpr(UnarySizeof, x)
   898  		}
   899  	}
   900  	switch cUnwrap(x).(type) {
   901  	case Bool:
   902  	case BoolExpr:
   903  		// workaround for C bools (they should be reported as int in some cases)
   904  		return g.SizeofT(g.env.DefIntT(), nil)
   905  	}
   906  	return g.SizeofT(x.CType(nil), nil)
   907  }
   908  
   909  func (g *translator) NewCUnaryExpr(op UnaryOp, x Expr) Expr {
   910  	switch op {
   911  	case UnarySizeof:
   912  		return g.cSizeofE(x)
   913  	case UnaryXor, UnaryMinus, UnaryPlus:
   914  		if xk := x.CType(nil).Kind(); xk.IsBool() {
   915  			x = g.cCast(g.env.DefIntT(), x)
   916  		} else if v, ok := x.(IntLit); ok && op == UnaryMinus {
   917  			return v.Negate()
   918  		}
   919  	}
   920  	return g.newUnaryExpr(op, x)
   921  }
   922  
   923  func (g *translator) NewCUnaryExprT(op UnaryOp, x Expr, typ types.Type) Expr {
   924  	if _, ok := x.(IntLit); ok && op == UnaryXor {
   925  		x = &CCastExpr{Expr: x, Type: typ}
   926  	}
   927  	x = g.NewCUnaryExpr(op, x)
   928  	if typ.Kind().IsBool() {
   929  		return x
   930  	}
   931  	if op == UnarySizeof {
   932  		return x
   933  	}
   934  	return g.cCast(typ, x)
   935  }
   936  
   937  func (g *translator) newUnaryExpr(op UnaryOp, x Expr) Expr {
   938  	return &CUnaryExpr{
   939  		g: g, Op: op, Expr: x,
   940  	}
   941  }
   942  
   943  type CUnaryExpr struct {
   944  	g    *translator
   945  	Op   UnaryOp
   946  	Expr Expr
   947  }
   948  
   949  func (e *CUnaryExpr) Visit(v Visitor) {
   950  	v(e.Expr)
   951  }
   952  
   953  func (e *CUnaryExpr) CType(exp types.Type) types.Type {
   954  	switch e.Op {
   955  	case UnarySizeof:
   956  		return e.g.env.UintPtrT()
   957  	}
   958  	return e.Expr.CType(exp)
   959  }
   960  
   961  func (e *CUnaryExpr) IsConst() bool {
   962  	switch e.Op {
   963  	case UnaryPlus, UnaryMinus, UnaryXor:
   964  		return e.Expr.IsConst()
   965  	}
   966  	return false
   967  }
   968  
   969  func (e *CUnaryExpr) HasSideEffects() bool {
   970  	return e.Expr.HasSideEffects()
   971  }
   972  
   973  func (e *CUnaryExpr) AsExpr() GoExpr {
   974  	var tok token.Token
   975  	switch e.Op {
   976  	case UnarySizeof:
   977  		return call(e.CType(nil).GoType(), call(ident("unsafe.Sizeof"), e.Expr.AsExpr()))
   978  	case UnaryPlus:
   979  		tok = token.ADD
   980  	case UnaryMinus:
   981  		tok = token.SUB
   982  	case UnaryXor:
   983  		tok = token.XOR
   984  	default:
   985  		panic(e.Op)
   986  	}
   987  	return &ast.UnaryExpr{
   988  		Op: tok,
   989  		X:  e.Expr.AsExpr(),
   990  	}
   991  }
   992  
   993  func (e *CUnaryExpr) Uses() []types.Usage {
   994  	return e.Expr.Uses()
   995  }
   996  
   997  func (g *translator) SizeofT(t types.Type, typ types.Type) Expr {
   998  	e := &CSizeofExpr{
   999  		rtyp: g.env.Go().Uintptr(),
  1000  		std:  true,
  1001  		Type: t,
  1002  	}
  1003  	if typ != nil && typ != e.rtyp {
  1004  		if !typ.Kind().IsInt() {
  1005  			return g.cCast(typ, e)
  1006  		}
  1007  		e.rtyp = typ
  1008  		e.std = false
  1009  	}
  1010  	return e
  1011  }
  1012  
  1013  func (g *translator) AlignofT(t types.Type, typ types.Type) Expr {
  1014  	e := &CAlignofExpr{
  1015  		rtyp: g.env.Go().Uintptr(),
  1016  		Type: t,
  1017  	}
  1018  	if typ != nil && typ != e.rtyp {
  1019  		if !typ.Kind().IsInt() {
  1020  			return g.cCast(typ, e)
  1021  		}
  1022  		e.rtyp = typ
  1023  		e.std = false
  1024  	}
  1025  	return e
  1026  }
  1027  
  1028  type CSizeofExpr struct {
  1029  	rtyp types.Type
  1030  	std  bool
  1031  	Type types.Type
  1032  }
  1033  
  1034  func (e *CSizeofExpr) Visit(v Visitor) {}
  1035  
  1036  func (e *CSizeofExpr) CType(types.Type) types.Type {
  1037  	return e.rtyp
  1038  }
  1039  
  1040  func (e *CSizeofExpr) IsConst() bool {
  1041  	return true
  1042  }
  1043  
  1044  func (e *CSizeofExpr) HasSideEffects() bool {
  1045  	return false
  1046  }
  1047  
  1048  func (e *CSizeofExpr) Uses() []types.Usage {
  1049  	// TODO: use type
  1050  	return nil
  1051  }
  1052  
  1053  func sizeOf(typ types.Type) GoExpr {
  1054  	switch typ := types.Unwrap(typ).(type) {
  1055  	case types.ArrayType:
  1056  		if !typ.IsSlice() && types.Unwrap(typ.Elem()) == types.UintT(1) {
  1057  			return intLit(typ.Len())
  1058  		}
  1059  	}
  1060  	x := typ.GoType()
  1061  	switch types.Unwrap(typ).(type) {
  1062  	case *types.StructType, types.ArrayType:
  1063  		x = &ast.CompositeLit{Type: x}
  1064  	case types.PtrType:
  1065  		x = call(x, Nil{}.AsExpr())
  1066  	case types.BoolType:
  1067  		x = call(x, boolLit(false))
  1068  	case *types.FuncType:
  1069  		x = call(ident("uintptr"), intLit(0))
  1070  	default:
  1071  		x = call(x, intLit(0))
  1072  	}
  1073  	return call(ident("unsafe.Sizeof"), x)
  1074  }
  1075  
  1076  func (e *CSizeofExpr) AsExpr() GoExpr {
  1077  	x := sizeOf(e.Type)
  1078  	if !e.std {
  1079  		x = call(e.CType(nil).GoType(), x)
  1080  	}
  1081  	return x
  1082  }
  1083  
  1084  type CAlignofExpr struct {
  1085  	rtyp types.Type
  1086  	std  bool
  1087  	Type types.Type
  1088  }
  1089  
  1090  func (e *CAlignofExpr) Visit(v Visitor) {}
  1091  
  1092  func (e *CAlignofExpr) CType(types.Type) types.Type {
  1093  	return e.rtyp
  1094  }
  1095  
  1096  func (e *CAlignofExpr) IsConst() bool {
  1097  	return true
  1098  }
  1099  
  1100  func (e *CAlignofExpr) HasSideEffects() bool {
  1101  	return false
  1102  }
  1103  
  1104  func (e *CAlignofExpr) Uses() []types.Usage {
  1105  	// TODO: use type
  1106  	return nil
  1107  }
  1108  
  1109  func zeroOf(typ types.Type) GoExpr {
  1110  	x := typ.GoType()
  1111  	switch types.Unwrap(typ).(type) {
  1112  	case *types.StructType, types.ArrayType:
  1113  		x = &ast.CompositeLit{Type: x}
  1114  	case types.PtrType:
  1115  		x = call(x, Nil{}.AsExpr())
  1116  	case types.BoolType:
  1117  		x = call(x, boolLit(false))
  1118  	default:
  1119  		x = call(x, intLit(0))
  1120  	}
  1121  	return x
  1122  }
  1123  
  1124  func (e *CAlignofExpr) AsExpr() GoExpr {
  1125  	x := call(ident("unsafe.Alignof"), zeroOf(e.Type))
  1126  	if !e.std {
  1127  		x = call(e.CType(nil).GoType(), x)
  1128  	}
  1129  	return x
  1130  }
  1131  
  1132  var _ CStmtConv = &CAssignExpr{}
  1133  
  1134  func (g *translator) NewCAssignExpr(x Expr, op BinaryOp, y Expr) Expr {
  1135  	return &CAssignExpr{
  1136  		Stmt: g.NewCAssignStmtP(x, op, y),
  1137  	}
  1138  }
  1139  
  1140  type CAssignExpr struct {
  1141  	Stmt *CAssignStmt
  1142  }
  1143  
  1144  func (e *CAssignExpr) Visit(v Visitor) {
  1145  	v(e.Stmt)
  1146  }
  1147  
  1148  func (e *CAssignExpr) CType(types.Type) types.Type {
  1149  	return e.Stmt.Left.CType(nil)
  1150  }
  1151  
  1152  func (e *CAssignExpr) IsConst() bool {
  1153  	return false
  1154  }
  1155  
  1156  func (e *CAssignExpr) HasSideEffects() bool {
  1157  	return true
  1158  }
  1159  
  1160  func (e *CAssignExpr) ToStmt() []CStmt {
  1161  	return e.Stmt.g.NewCAssignStmt(e.Stmt.Left, e.Stmt.Op, e.Stmt.Right)
  1162  }
  1163  
  1164  func (e *CAssignExpr) AsExpr() GoExpr {
  1165  	ret := e.CType(nil)
  1166  	var stmts []GoStmt
  1167  	if id, ok := e.Stmt.Left.(IdentExpr); ok {
  1168  		stmts = append(stmts,
  1169  			e.Stmt.g.NewCAssignStmtP(id, e.Stmt.Op, e.Stmt.Right).AsStmt()...,
  1170  		)
  1171  		stmts = append(stmts,
  1172  			returnStmt(id.GoIdent()),
  1173  		)
  1174  		return callLambda(
  1175  			ret.GoType(),
  1176  			stmts...,
  1177  		)
  1178  	}
  1179  	x, y := &TakeAddr{g: e.Stmt.g, X: e.Stmt.Left}, e.Stmt.Right
  1180  	p := types.NewIdent("p", x.CType(nil))
  1181  	pg := p.GoIdent()
  1182  	stmts = append(stmts,
  1183  		define(pg, x.AsExpr()),
  1184  	)
  1185  	stmts = append(stmts,
  1186  		e.Stmt.g.NewCAssignStmtP(e.Stmt.g.cDeref(x), e.Stmt.Op, y).AsStmt()...,
  1187  	)
  1188  	stmts = append(stmts,
  1189  		returnStmt(deref(pg)),
  1190  	)
  1191  	return callLambda(
  1192  		ret.GoType(),
  1193  		stmts...,
  1194  	)
  1195  }
  1196  
  1197  func (e *CAssignExpr) Uses() []types.Usage {
  1198  	var list []types.Usage
  1199  	list = append(list, types.UseRead(e.Stmt.Left)...)
  1200  	list = append(list, types.UseWrite(e.Stmt.Left)...)
  1201  	list = append(list, types.UseRead(e.Stmt.Right)...)
  1202  	return list
  1203  }
  1204  
  1205  func mergeStructInitializers(items []*CompLitField) []*CompLitField {
  1206  	out := make([]*CompLitField, 0, len(items))
  1207  	byField := make(map[string]*CompLitField)
  1208  	for _, it := range items {
  1209  		if it.Field == nil {
  1210  			out = append(out, it)
  1211  			continue
  1212  		}
  1213  		c1, ok := cUnwrap(it.Value).(*CCompLitExpr)
  1214  		if !ok {
  1215  			out = append(out, it)
  1216  			continue
  1217  		}
  1218  		it2 := byField[it.Field.Name]
  1219  		if it2 == nil {
  1220  			byField[it.Field.Name] = it
  1221  			out = append(out, it)
  1222  			continue
  1223  		}
  1224  		c2, ok := cUnwrap(it2.Value).(*CCompLitExpr)
  1225  		if !ok {
  1226  			out = append(out, it)
  1227  			continue
  1228  		}
  1229  		if !types.Same(c1.Type, c2.Type) {
  1230  			out = append(out, it)
  1231  			continue
  1232  		}
  1233  		sub := make([]*CompLitField, 0, len(c1.Fields)+len(c2.Fields))
  1234  		sub = append(sub, c2.Fields...)
  1235  		sub = append(sub, c1.Fields...)
  1236  		c2.Fields = sub
  1237  	}
  1238  	return out
  1239  }
  1240  
  1241  func (g *translator) NewCCompLitExpr(typ types.Type, items []*CompLitField) Expr {
  1242  	if k := typ.Kind(); k.Is(types.Struct) {
  1243  		st := types.Unwrap(typ).(*types.StructType)
  1244  		next := 0
  1245  		for _, it := range items {
  1246  			var ft types.Type
  1247  			if it.Field != nil {
  1248  				ft = it.Field.CType(nil)
  1249  			} else if it.Index == nil {
  1250  				f := st.Fields()[next]
  1251  				next++
  1252  				it.Field = f.Name
  1253  				ft = f.Type()
  1254  			} else if l, ok := cUnwrap(it.Index).(IntLit); ok {
  1255  				next = int(l.Uint())
  1256  				f := st.Fields()[next]
  1257  				next++
  1258  				it.Field = f.Name
  1259  				ft = f.Type()
  1260  			}
  1261  			if ft != nil {
  1262  				it.Value = g.cCast(ft, it.Value)
  1263  			}
  1264  		}
  1265  		items = mergeStructInitializers(items)
  1266  	} else if k.Is(types.Array) {
  1267  		arr := types.Unwrap(typ).(types.ArrayType)
  1268  		tp := arr.Elem()
  1269  		for _, it := range items {
  1270  			it.Value = g.cCast(tp, it.Value)
  1271  		}
  1272  	}
  1273  	return &CCompLitExpr{Type: typ, Fields: items}
  1274  }
  1275  
  1276  type CompLitField struct {
  1277  	Index Expr
  1278  	Field *types.Ident
  1279  	Value Expr
  1280  }
  1281  
  1282  func (e *CompLitField) Visit(v Visitor) {
  1283  	v(e.Index)
  1284  	if e.Field != nil {
  1285  		v(IdentExpr{e.Field})
  1286  	}
  1287  	v(e.Value)
  1288  }
  1289  
  1290  type CCompLitExpr struct {
  1291  	Type   types.Type
  1292  	Fields []*CompLitField
  1293  }
  1294  
  1295  func (e *CCompLitExpr) Visit(v Visitor) {
  1296  	for _, f := range e.Fields {
  1297  		v(f)
  1298  	}
  1299  }
  1300  
  1301  func (e *CCompLitExpr) CType(types.Type) types.Type {
  1302  	return e.Type
  1303  }
  1304  
  1305  func (e *CCompLitExpr) IsConst() bool {
  1306  	return false
  1307  }
  1308  
  1309  func (e *CCompLitExpr) HasSideEffects() bool {
  1310  	has := false
  1311  	for _, f := range e.Fields {
  1312  		has = has || f.Value.HasSideEffects()
  1313  	}
  1314  	return has
  1315  }
  1316  
  1317  func (e *CCompLitExpr) isZero() bool {
  1318  	for _, f := range e.Fields {
  1319  		switch v := cUnwrapConst(f.Value).(type) {
  1320  		case IntLit:
  1321  			if !v.IsZero() {
  1322  				return false
  1323  			}
  1324  		case Nil:
  1325  			// nop
  1326  		case *CCompLitExpr:
  1327  			if !v.isZero() {
  1328  				return false
  1329  			}
  1330  		default:
  1331  			return false
  1332  		}
  1333  	}
  1334  	return true
  1335  }
  1336  
  1337  func (e *CCompLitExpr) AsExpr() GoExpr {
  1338  	if e.isZero() {
  1339  		// special case: MyStruct{0} usually means the same in C as MyStruct{} in Go
  1340  		return &ast.CompositeLit{
  1341  			Type: e.Type.GoType(),
  1342  		}
  1343  	}
  1344  	var items []GoExpr
  1345  	isArr := e.CType(nil).Kind().Is(types.Array)
  1346  	ordered := false
  1347  	if isArr {
  1348  		// check if array elements are ordered so we can skip indexes in the init
  1349  		at, ok := types.Unwrap(e.CType(nil)).(types.ArrayType)
  1350  		if ok && at.Len() == len(e.Fields) {
  1351  			ordered = true
  1352  			for i, f := range e.Fields {
  1353  				if f.Index == nil {
  1354  					continue
  1355  				}
  1356  				v, ok := cUnwrap(f.Index).(IntLit)
  1357  				if !ok {
  1358  					ordered = false
  1359  					break
  1360  				}
  1361  				if !v.IsUint() || i != int(v.Uint()) {
  1362  					ordered = false
  1363  					break
  1364  				}
  1365  			}
  1366  		}
  1367  	}
  1368  	for _, f := range e.Fields {
  1369  		v := f.Value.AsExpr()
  1370  		if v, ok := v.(*ast.CompositeLit); ok && isArr {
  1371  			v.Type = nil
  1372  		}
  1373  		if f.Field != nil {
  1374  			items = append(items, &ast.KeyValueExpr{
  1375  				Key:   f.Field.GoIdent(),
  1376  				Value: v,
  1377  			})
  1378  		} else if f.Index != nil && !ordered {
  1379  			items = append(items, &ast.KeyValueExpr{
  1380  				Key:   f.Index.AsExpr(),
  1381  				Value: v,
  1382  			})
  1383  		} else {
  1384  			items = append(items, v)
  1385  		}
  1386  	}
  1387  	return &ast.CompositeLit{
  1388  		Type: e.Type.GoType(),
  1389  		Elts: items,
  1390  	}
  1391  }
  1392  
  1393  func (e *CCompLitExpr) Uses() []types.Usage {
  1394  	var list []types.Usage
  1395  	// TODO: use the type
  1396  	for _, e := range e.Fields {
  1397  		if e.Field != nil {
  1398  			list = append(list, types.Usage{Ident: e.Field, Access: types.AccessWrite})
  1399  		}
  1400  		if e.Value != nil {
  1401  			list = append(list, types.UseRead(e.Value)...)
  1402  		}
  1403  		if e.Index != nil {
  1404  			list = append(list, types.UseRead(e.Index)...)
  1405  		}
  1406  	}
  1407  	return list
  1408  }
  1409  
  1410  type TypeAssert struct {
  1411  	Type types.Type
  1412  	Expr Expr
  1413  }
  1414  
  1415  func (e *TypeAssert) IsConst() bool {
  1416  	return false
  1417  }
  1418  
  1419  func (e *TypeAssert) HasSideEffects() bool {
  1420  	return true
  1421  }
  1422  
  1423  func (e *TypeAssert) CType(types.Type) types.Type {
  1424  	return e.Type
  1425  }
  1426  
  1427  func (e *TypeAssert) AsExpr() GoExpr {
  1428  	return &ast.TypeAssertExpr{
  1429  		X:    e.Expr.AsExpr(),
  1430  		Type: e.Type.GoType(),
  1431  	}
  1432  }
  1433  
  1434  type SliceExpr struct {
  1435  	Expr   Expr
  1436  	Low    Expr
  1437  	High   Expr
  1438  	Max    Expr
  1439  	Slice3 bool
  1440  }
  1441  
  1442  func (e *SliceExpr) Visit(v Visitor) {
  1443  	v(e.Expr)
  1444  }
  1445  
  1446  func (e *SliceExpr) IsConst() bool {
  1447  	return false
  1448  }
  1449  
  1450  func (e *SliceExpr) HasSideEffects() bool {
  1451  	return false
  1452  }
  1453  
  1454  func (e *SliceExpr) CType(exp types.Type) types.Type {
  1455  	return e.Expr.CType(exp)
  1456  }
  1457  
  1458  func (e *SliceExpr) AsExpr() GoExpr {
  1459  	var low, high, max GoExpr
  1460  	if e.Low != nil {
  1461  		low = e.Low.AsExpr()
  1462  	}
  1463  	if e.High != nil {
  1464  		high = e.High.AsExpr()
  1465  	}
  1466  	if e.Max != nil {
  1467  		max = e.Max.AsExpr()
  1468  	}
  1469  	return &ast.SliceExpr{
  1470  		X:   e.Expr.AsExpr(),
  1471  		Low: low, High: high, Max: max,
  1472  		Slice3: e.Slice3,
  1473  	}
  1474  }
  1475  
  1476  func (e *SliceExpr) Uses() []types.Usage {
  1477  	uses := e.Expr.Uses()
  1478  	uses = append(uses, types.UseRead(e.Low, e.High, e.Max)...)
  1479  	return uses
  1480  }
  1481  
  1482  func exprCost(e Expr) int {
  1483  	if e == nil {
  1484  		return 0
  1485  	}
  1486  	switch e := e.(type) {
  1487  	case *CMultiExpr:
  1488  		c := 0
  1489  		for _, s := range e.Exprs {
  1490  			c += exprCost(s)
  1491  		}
  1492  		return c
  1493  	case *CallExpr:
  1494  		c := 1
  1495  		for _, s := range e.Args {
  1496  			c += exprCost(s)
  1497  		}
  1498  		return c
  1499  	case *CTernaryExpr:
  1500  		return 1 + exprCost(e.Cond) + exprCost(e.Then) + exprCost(e.Else)
  1501  	case *CAssignExpr:
  1502  		return 1 + stmtCost(e.Stmt)
  1503  	case *CBinaryExpr:
  1504  		return 1 + exprCost(e.Left) + exprCost(e.Right)
  1505  	case *CIndexExpr:
  1506  		return 1 + exprCost(e.Expr) + exprCost(e.Index)
  1507  	case *CSelectExpr:
  1508  		return 1 + exprCost(e.Expr)
  1509  	case *CCastExpr:
  1510  		return 1 + exprCost(e.Expr)
  1511  	case *CIncrExpr:
  1512  		return 1 + exprCost(e.Expr)
  1513  	case *CUnaryExpr:
  1514  		return 1 + exprCost(e.Expr)
  1515  	case *CParentExpr:
  1516  		return exprCost(e.Expr)
  1517  	default:
  1518  		return 1
  1519  	}
  1520  }