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

     1  package cxgo
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  
     7  	"github.com/gotranspile/cxgo/types"
     8  )
     9  
    10  func ToFuncExpr(exp types.Type) *types.FuncType {
    11  	if t, ok := exp.(types.PtrType); ok {
    12  		exp = t.Elem()
    13  	}
    14  	if t, ok := types.Unwrap(exp).(*types.FuncType); ok {
    15  		return t
    16  	}
    17  	return nil
    18  }
    19  
    20  var _ FuncExpr = Nil{}
    21  
    22  // FuncExpr is an expression that returns a function value.
    23  type FuncExpr interface {
    24  	Expr
    25  	// FuncType return an underlying function type.
    26  	FuncType(exp *types.FuncType) *types.FuncType
    27  }
    28  
    29  var (
    30  	_ FuncExpr = FuncIdent{}
    31  	_ Ident    = FuncIdent{}
    32  )
    33  
    34  type FuncIdent struct {
    35  	*types.Ident
    36  }
    37  
    38  func (FuncIdent) Visit(v Visitor) {}
    39  
    40  func (e FuncIdent) Identifier() *types.Ident {
    41  	return e.Ident
    42  }
    43  
    44  func (e FuncIdent) IsConst() bool {
    45  	return false
    46  }
    47  
    48  func (e FuncIdent) HasSideEffects() bool {
    49  	return false
    50  }
    51  
    52  func (e FuncIdent) AsExpr() GoExpr {
    53  	return e.GoIdent()
    54  }
    55  
    56  func (e FuncIdent) FuncType(exp *types.FuncType) *types.FuncType {
    57  	var et types.Type
    58  	if exp != nil {
    59  		et = exp
    60  	}
    61  	return types.Unwrap(e.CType(et)).(*types.FuncType)
    62  }
    63  
    64  func (e FuncIdent) Uses() []types.Usage {
    65  	return []types.Usage{{Ident: e.Ident, Access: types.AccessUnknown}}
    66  }
    67  
    68  var _ FuncExpr = FuncAssert{}
    69  
    70  type FuncAssert struct {
    71  	X Expr
    72  }
    73  
    74  func (e FuncAssert) Visit(v Visitor) {
    75  	v(e.X)
    76  }
    77  
    78  func (e FuncAssert) CType(types.Type) types.Type {
    79  	return e.X.CType(nil)
    80  }
    81  
    82  func (e FuncAssert) IsConst() bool {
    83  	return e.X.IsConst()
    84  }
    85  
    86  func (e FuncAssert) HasSideEffects() bool {
    87  	return e.X.HasSideEffects()
    88  }
    89  
    90  func (e FuncAssert) AsExpr() GoExpr {
    91  	return e.X.AsExpr()
    92  }
    93  
    94  func (e FuncAssert) FuncType(*types.FuncType) *types.FuncType {
    95  	return types.Unwrap(e.CType(nil)).(*types.FuncType)
    96  }
    97  
    98  func (e FuncAssert) Uses() []types.Usage {
    99  	return e.X.Uses()
   100  }
   101  
   102  func asSizeofT(e Expr) types.Type {
   103  	e = unwrapCasts(e)
   104  	sz, ok := e.(*CSizeofExpr)
   105  	if !ok {
   106  		return nil
   107  	}
   108  	return sz.Type
   109  }
   110  
   111  func (g *translator) NewCCallExpr(fnc FuncExpr, args []Expr) Expr {
   112  	if id, ok := cUnwrap(fnc).(IdentExpr); ok {
   113  		// TODO: another way to hook into it?
   114  		switch id.Ident {
   115  		case g.env.C().AssertFunc():
   116  			// assert(!const) -> panic(const)
   117  			if len(args) == 1 {
   118  				a1 := args[0]
   119  				if a1.IsConst() {
   120  					if IsNil(a1) {
   121  						return &CallExpr{
   122  							Fun:  FuncIdent{g.env.Go().PanicFunc()},
   123  							Args: []Expr{a1},
   124  						}
   125  					}
   126  					switch a1 := a1.(type) {
   127  					case *Not:
   128  						return &CallExpr{
   129  							Fun:  FuncIdent{g.env.Go().PanicFunc()},
   130  							Args: []Expr{unwrapCasts(a1.X)},
   131  						}
   132  					case *Comparison:
   133  						switch a1.Op {
   134  						case BinOpEq:
   135  							if !IsNil(a1.X) && IsNil(a1.Y) {
   136  								return &CallExpr{
   137  									Fun:  FuncIdent{g.env.Go().PanicFunc()},
   138  									Args: []Expr{unwrapCasts(a1.X)},
   139  								}
   140  							}
   141  						}
   142  					case *PtrComparison:
   143  						switch a1.Op {
   144  						case BinOpEq:
   145  							if !IsNil(a1.X) && IsNil(a1.Y) {
   146  								return &CallExpr{
   147  									Fun:  FuncIdent{g.env.Go().PanicFunc()},
   148  									Args: []Expr{unwrapCasts(a1.X)},
   149  								}
   150  							}
   151  						}
   152  					}
   153  				}
   154  				return &CallExpr{
   155  					Fun:  FuncIdent{g.env.C().AssertFunc()},
   156  					Args: []Expr{g.ToBool(a1)},
   157  				}
   158  			}
   159  		case g.env.C().MallocFunc():
   160  			// malloc(sizeof(T)) -> new(T)
   161  			if len(args) == 1 {
   162  				if tp := asSizeofT(args[0]); tp != nil {
   163  					return &NewExpr{
   164  						e:    g.env.Env,
   165  						Elem: tp,
   166  					}
   167  				}
   168  			}
   169  		case g.env.C().CallocFunc():
   170  			// calloc(n, sizeof(T)) -> make([]T, n)
   171  			if len(args) == 2 {
   172  				if tp := asSizeofT(args[1]); tp != nil {
   173  					return &MakeExpr{
   174  						e:    g.env.Env,
   175  						Elem: tp,
   176  						Size: g.cCast(g.env.Go().Int(), args[0]),
   177  					}
   178  				}
   179  			}
   180  		case g.env.C().MemsetFunc():
   181  			// memset(p, 0, sizeof(T)) -> *p = T{}
   182  			if len(args) == 3 {
   183  				if lit, ok := unwrapCasts(args[1]).(IntLit); ok && lit.IsZero() {
   184  					if tp := asSizeofT(args[2]); tp != nil {
   185  						p := g.cDeref(g.ToPointer(g.cCast(g.env.PtrT(tp), args[0])))
   186  						return g.NewCAssignExpr(p, "", g.ZeroValue(tp))
   187  					}
   188  				}
   189  			}
   190  		case g.env.C().StrdupFunc():
   191  			// strdup(string) -> string
   192  			if len(args) == 1 {
   193  				if args[0].CType(nil) == g.env.Go().String() {
   194  					return args[0]
   195  				}
   196  			}
   197  		case g.env.C().StrndupFunc():
   198  			// strndup(string, n) -> string[:n]
   199  			if len(args) == 2 {
   200  				if args[0].CType(nil) == g.env.Go().String() {
   201  					return &SliceExpr{Expr: args[0], High: args[1]}
   202  				}
   203  			}
   204  		case g.env.Go().SliceFunc():
   205  			// _slice(arr, -1, 1) -> arr[:1]
   206  			if len(args) == 3 || len(args) == 4 {
   207  				var low, high, max Expr
   208  				if i, ok := args[1].(Number); !ok || !i.IsNegative() {
   209  					low = args[1]
   210  				}
   211  				if i, ok := args[2].(Number); !ok || !i.IsNegative() {
   212  					high = args[2]
   213  				}
   214  				if len(args) > 3 {
   215  					if i, ok := args[3].(Number); !ok || !i.IsNegative() {
   216  						max = args[3]
   217  					}
   218  				}
   219  				return &SliceExpr{
   220  					Expr: args[0],
   221  					Low:  low, High: high, Max: max,
   222  					Slice3: len(args) > 3,
   223  				}
   224  			}
   225  		case g.env.Go().MakeFunc():
   226  			if len(args) == 2 || len(args) == 3 {
   227  				if arr, ok := args[0].CType(nil).(types.ArrayType); ok {
   228  					var a3 Expr
   229  					if len(args) > 2 {
   230  						a3 = args[2]
   231  					}
   232  					return &MakeExpr{
   233  						e:    g.env.Env,
   234  						Elem: arr.Elem(),
   235  						Size: args[1],
   236  						Cap:  a3,
   237  					}
   238  				}
   239  			}
   240  		case g.env.Go().AppendFunc():
   241  			if len(args) == 2 {
   242  				xt, yt := args[0].CType(nil), args[1].CType(nil)
   243  				if xt.Kind() == types.Array && yt.Kind() == types.Array {
   244  					args[1] = &ExpandExpr{X: args[1]}
   245  					return &CallExpr{
   246  						Fun:  fnc,
   247  						Args: args,
   248  					}
   249  				}
   250  			}
   251  		}
   252  		//	kf, ok := knownCFuncs[id.Name]
   253  		//	if !ok {
   254  		//		kf, ok = known[id.Ident]
   255  		//	}
   256  		//	if ok && (id.Ident != kf.Name || (kf.This != nil && len(args) > len(kf.This.Args))) {
   257  		//		if kf.This == nil {
   258  		//			return NewCCallExpr(IdentExpr{kf.Name}, args)
   259  		//		}
   260  		//		fnc = &CSelectExpr{
   261  		//			ctype: kf.This,
   262  		//			Expr: cCast(kf.Type.Args[0].Type, args[0]),
   263  		//			Sel: kf.Name,
   264  		//		}
   265  		//		return NewCCallExpr(fnc, args[1:])
   266  		//	}
   267  	}
   268  	t := fnc.CType(nil)
   269  	if p, ok := t.(types.PtrType); ok && p.Elem() != nil {
   270  		t = p.Elem()
   271  	}
   272  	ft := types.Unwrap(t).(*types.FuncType)
   273  	ftargs := ft.Args()
   274  	for i, a := range args {
   275  		var atyp types.Type
   276  		if i < len(ftargs) {
   277  			atyp = ftargs[i].Type()
   278  		} else if ft.Variadic() {
   279  			atyp = types.UnkT(1)
   280  		} else {
   281  			break
   282  		}
   283  		args[i] = g.cCast(atyp, a)
   284  	}
   285  	return &CallExpr{
   286  		Fun:  fnc,
   287  		Args: args,
   288  	}
   289  }
   290  
   291  var _ Expr = (*CallExpr)(nil)
   292  
   293  type CallExpr struct {
   294  	Fun  FuncExpr
   295  	Args []Expr
   296  }
   297  
   298  func (e *CallExpr) Visit(v Visitor) {
   299  	v(e.Fun)
   300  	for _, a := range e.Args {
   301  		v(a)
   302  	}
   303  }
   304  
   305  func (e *CallExpr) CType(types.Type) types.Type {
   306  	typ := e.Fun.FuncType(nil)
   307  	if typ.Return() == nil {
   308  		panic("function doesn't return")
   309  	}
   310  	return typ.Return()
   311  }
   312  
   313  func (e *CallExpr) IsConst() bool {
   314  	return false
   315  }
   316  
   317  func (e *CallExpr) HasSideEffects() bool {
   318  	return true
   319  }
   320  
   321  func (e *CallExpr) AsExpr() GoExpr {
   322  	var args []GoExpr
   323  	vari := false
   324  	for _, a := range e.Args {
   325  		if x, ok := a.(*ExpandExpr); ok {
   326  			vari = true
   327  			a = x.X
   328  		}
   329  		args = append(args, a.AsExpr())
   330  	}
   331  	if vari {
   332  		return callVari(e.Fun.AsExpr(), args...)
   333  	}
   334  	return call(e.Fun.AsExpr(), args...)
   335  }
   336  
   337  func (e *CallExpr) Uses() []types.Usage {
   338  	var list []types.Usage
   339  	list = append(list, types.UseRead(e.Fun)...)
   340  	for _, a := range e.Args {
   341  		list = append(list, types.UseRead(a)...)
   342  	}
   343  	return list
   344  }
   345  
   346  var _ FuncExpr = (*FuncLit)(nil)
   347  
   348  func (g *translator) NewFuncLit(typ *types.FuncType, body ...CStmt) *FuncLit {
   349  	if typ.Return() != nil && typ.Return().Kind().IsUntyped() {
   350  		panic("untyped")
   351  	}
   352  	return &FuncLit{
   353  		Type: typ,
   354  		Body: g.NewCBlock(body...),
   355  	}
   356  }
   357  
   358  type FuncLit struct {
   359  	Type *types.FuncType
   360  	Body *BlockStmt
   361  }
   362  
   363  func (e *FuncLit) Visit(v Visitor) {
   364  	v(e.Body)
   365  }
   366  
   367  func (e *FuncLit) IsConst() bool {
   368  	return false
   369  }
   370  
   371  func (e *FuncLit) HasSideEffects() bool {
   372  	return true
   373  }
   374  
   375  func (e *FuncLit) CType(types.Type) types.Type {
   376  	return e.Type
   377  }
   378  
   379  func (e *FuncLit) FuncType(*types.FuncType) *types.FuncType {
   380  	return e.Type
   381  }
   382  
   383  func (e *FuncLit) AsExpr() GoExpr {
   384  	return &ast.FuncLit{
   385  		Type: e.Type.GoFuncType(),
   386  		Body: e.Body.GoBlockStmt(),
   387  	}
   388  }
   389  
   390  func (e *FuncLit) Uses() []types.Usage {
   391  	var list []types.Usage
   392  	// TODO: use the type
   393  	if e.Body != nil {
   394  		list = append(list, e.Body.Uses()...)
   395  	}
   396  	return list
   397  }
   398  
   399  var _ FuncExpr = (*PtrToFunc)(nil)
   400  
   401  type PtrToFunc struct {
   402  	X  PtrExpr
   403  	To *types.FuncType
   404  }
   405  
   406  func (e *PtrToFunc) Visit(v Visitor) {
   407  	v(e.X)
   408  }
   409  
   410  func (e *PtrToFunc) CType(types.Type) types.Type {
   411  	return e.To
   412  }
   413  
   414  func (e *PtrToFunc) AsExpr() GoExpr {
   415  	x := e.X.AsExpr()
   416  	ft := e.To.GoType()
   417  	asFunc := call(
   418  		ident("libc.AsFunc"), x,
   419  		call(paren(deref(ft)), ident("nil")),
   420  	)
   421  	return typAssert(asFunc, ft)
   422  }
   423  
   424  func (e *PtrToFunc) IsConst() bool {
   425  	return false
   426  }
   427  
   428  func (e *PtrToFunc) HasSideEffects() bool {
   429  	return e.X.HasSideEffects()
   430  }
   431  
   432  func (e *PtrToFunc) Uses() []types.Usage {
   433  	return e.X.Uses()
   434  }
   435  
   436  func (e *PtrToFunc) FuncType(*types.FuncType) *types.FuncType {
   437  	return e.To
   438  }
   439  
   440  var _ PtrExpr = (*FuncToPtr)(nil)
   441  
   442  type FuncToPtr struct {
   443  	e *types.Env
   444  	X FuncExpr
   445  }
   446  
   447  func (e *FuncToPtr) Visit(v Visitor) {
   448  	v(e.X)
   449  }
   450  
   451  func (e *FuncToPtr) CType(types.Type) types.Type {
   452  	return e.PtrType(nil)
   453  }
   454  
   455  func (e *FuncToPtr) AsExpr() GoExpr {
   456  	x := e.X.AsExpr()
   457  	return call(unsafePtr(), call(ident("libc.FuncAddr"), x))
   458  }
   459  
   460  func (e *FuncToPtr) IsConst() bool {
   461  	return false
   462  }
   463  
   464  func (e *FuncToPtr) HasSideEffects() bool {
   465  	return e.X.HasSideEffects()
   466  }
   467  
   468  func (e *FuncToPtr) Uses() []types.Usage {
   469  	return e.X.Uses()
   470  }
   471  
   472  func (e *FuncToPtr) PtrType(types.PtrType) types.PtrType {
   473  	return e.e.PtrT(nil)
   474  }
   475  
   476  var _ FuncExpr = (*IntToFunc)(nil)
   477  
   478  type IntToFunc struct {
   479  	X  Expr
   480  	To *types.FuncType
   481  }
   482  
   483  func (e *IntToFunc) Visit(v Visitor) {
   484  	v(e.X)
   485  }
   486  
   487  func (e *IntToFunc) CType(types.Type) types.Type {
   488  	return e.To
   489  }
   490  
   491  func (e *IntToFunc) AsExpr() GoExpr {
   492  	x := e.X.AsExpr()
   493  	ft := e.To.GoType()
   494  	asFunc := call(
   495  		ident("libc.AsFunc"), x,
   496  		call(paren(deref(ft)), ident("nil")),
   497  	)
   498  	return typAssert(asFunc, ft)
   499  }
   500  
   501  func (e *IntToFunc) IsConst() bool {
   502  	return false
   503  }
   504  
   505  func (e *IntToFunc) HasSideEffects() bool {
   506  	return e.X.HasSideEffects()
   507  }
   508  
   509  func (e *IntToFunc) Uses() []types.Usage {
   510  	return e.X.Uses()
   511  }
   512  
   513  func (e *IntToFunc) FuncType(*types.FuncType) *types.FuncType {
   514  	return e.To
   515  }
   516  
   517  var _ Expr = (*FuncToInt)(nil)
   518  
   519  type FuncToInt struct {
   520  	X  FuncExpr
   521  	To types.IntType
   522  }
   523  
   524  func (e *FuncToInt) Visit(v Visitor) {
   525  	v(e.X)
   526  }
   527  
   528  func (e *FuncToInt) CType(types.Type) types.Type {
   529  	return e.To
   530  }
   531  
   532  func (e *FuncToInt) AsExpr() GoExpr {
   533  	x := e.X.AsExpr()
   534  	x = call(ident("libc.FuncAddr"), x)
   535  	x = call(e.To.GoType(), x)
   536  	return x
   537  }
   538  
   539  func (e *FuncToInt) IsConst() bool {
   540  	return false
   541  }
   542  
   543  func (e *FuncToInt) HasSideEffects() bool {
   544  	return e.X.HasSideEffects()
   545  }
   546  
   547  func (e *FuncToInt) Uses() []types.Usage {
   548  	return e.X.Uses()
   549  }
   550  
   551  func (g *translator) ToFunc(x Expr, exp *types.FuncType) FuncExpr {
   552  	if x, ok := x.(FuncExpr); ok {
   553  		return x
   554  	}
   555  	if x, ok := cUnwrap(x).(IntLit); ok && x.IsZero() {
   556  		return g.Nil()
   557  	}
   558  	xt := x.CType(nil)
   559  	xk := xt.Kind()
   560  	if xk.IsFunc() {
   561  		switch x := x.(type) {
   562  		case Ident:
   563  			return FuncIdent{x.Identifier()}
   564  		}
   565  		return FuncAssert{x}
   566  	}
   567  	if xk.IsPtr() {
   568  		if exp == nil {
   569  			panic("expected type must be set")
   570  		}
   571  		xp := g.ToPointer(x)
   572  		switch xp := xp.(type) {
   573  		case *FuncToPtr:
   574  			return xp.X
   575  		}
   576  		return &PtrToFunc{
   577  			X:  xp,
   578  			To: exp,
   579  		}
   580  	}
   581  	if xk.IsInt() {
   582  		if exp == nil {
   583  			panic("expected type must be set")
   584  		}
   585  		return &IntToFunc{
   586  			X:  x,
   587  			To: exp,
   588  		}
   589  	}
   590  	panic(fmt.Errorf("not a function: %T, %T", xt, x))
   591  }
   592  
   593  func CompareFuncs(x FuncExpr, op ComparisonOp, y FuncExpr) BoolExpr {
   594  	if op.IsRelational() {
   595  		return &FuncComparison{
   596  			X: x, Op: op, Y: y,
   597  		}
   598  	}
   599  	if !op.IsEquality() {
   600  		panic("must not happen")
   601  	}
   602  	// == and != simplifications
   603  	// always compare with the constant on the right
   604  	if x.IsConst() && !y.IsConst() {
   605  		return CompareFuncs(y, op, x)
   606  	}
   607  	return &FuncComparison{
   608  		X: x, Op: op, Y: y,
   609  	}
   610  }
   611  
   612  var _ BoolExpr = (*FuncComparison)(nil)
   613  
   614  type FuncComparison struct {
   615  	X  FuncExpr
   616  	Op ComparisonOp
   617  	Y  FuncExpr
   618  }
   619  
   620  func (e *FuncComparison) Visit(v Visitor) {
   621  	v(e.X)
   622  	v(e.Y)
   623  }
   624  
   625  func (e *FuncComparison) CType(types.Type) types.Type {
   626  	return types.BoolT()
   627  }
   628  
   629  func (e *FuncComparison) AsExpr() GoExpr {
   630  	x := e.X.AsExpr()
   631  	y := e.Y.AsExpr()
   632  	if _, ok := e.Y.(Nil); !ok {
   633  		// compare via uintptr
   634  		x = call(ident("libc.FuncAddr"), x)
   635  		y = call(ident("libc.FuncAddr"), y)
   636  	}
   637  	return &ast.BinaryExpr{
   638  		X:  x,
   639  		Op: e.Op.GoToken(),
   640  		Y:  y,
   641  	}
   642  }
   643  
   644  func (e *FuncComparison) IsConst() bool {
   645  	return e.X.IsConst() && e.Y.IsConst()
   646  }
   647  
   648  func (e *FuncComparison) HasSideEffects() bool {
   649  	return e.X.HasSideEffects() || e.Y.HasSideEffects()
   650  }
   651  
   652  func (e *FuncComparison) Negate() BoolExpr {
   653  	return CompareFuncs(e.X, e.Op.Negate(), e.Y)
   654  }
   655  
   656  func (e *FuncComparison) Uses() []types.Usage {
   657  	return types.UseRead(e.X, e.Y)
   658  }
   659  
   660  type ExpandExpr struct {
   661  	X Expr
   662  }
   663  
   664  func (e *ExpandExpr) Visit(v Visitor) {
   665  	v(e.X)
   666  }
   667  
   668  func (e *ExpandExpr) CType(_ types.Type) types.Type {
   669  	return types.UnkT(1)
   670  }
   671  
   672  func (e *ExpandExpr) AsExpr() GoExpr {
   673  	panic("should be handled by CallExpr")
   674  }
   675  
   676  func (e *ExpandExpr) IsConst() bool {
   677  	return false
   678  }
   679  
   680  func (e *ExpandExpr) HasSideEffects() bool {
   681  	return false
   682  }
   683  
   684  func (e *ExpandExpr) Uses() []types.Usage {
   685  	return types.UseWrite(e.X)
   686  }