github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/transpiler/value_to_pointer.go (about)

     1  package transpiler
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	goast "go/ast"
     7  	"go/parser"
     8  	"go/printer"
     9  	"go/token"
    10  	"html/template"
    11  	"sort"
    12  	"strings"
    13  
    14  	"github.com/Konstantin8105/c4go/ast"
    15  	"github.com/Konstantin8105/c4go/program"
    16  	"github.com/Konstantin8105/c4go/types"
    17  	"github.com/Konstantin8105/c4go/util"
    18  )
    19  
    20  const unsafeConvertFunctionName string = "c4goUnsafeConvert_"
    21  
    22  func ConvertValueToPointer(nodes []ast.Node, p *program.Program) (expr goast.Expr, ok bool) {
    23  	if len(nodes) != 1 {
    24  		return nil, false
    25  	}
    26  
    27  	decl, ok := nodes[0].(*ast.DeclRefExpr)
    28  	if !ok {
    29  		return nil, false
    30  	}
    31  
    32  	if types.IsPointer(decl.Type, p) {
    33  		return nil, false
    34  	}
    35  
    36  	// get base type if it typedef
    37  	var td string = decl.Type
    38  	for {
    39  		if t, ok := p.TypedefType[td]; ok {
    40  			td = t
    41  			continue
    42  		}
    43  		break
    44  	}
    45  
    46  	resolvedType, err := types.ResolveType(p, td)
    47  	if err != nil {
    48  		p.AddMessage(p.GenerateWarningMessage(err, decl))
    49  		return
    50  	}
    51  
    52  	var acceptable bool
    53  
    54  	if types.IsGoBaseType(resolvedType) {
    55  		acceptable = true
    56  	}
    57  
    58  	if str, ok := p.Structs[decl.Type]; ok && str.IsGlobal {
    59  		acceptable = true
    60  	}
    61  
    62  	if str, ok := p.Unions[decl.Type]; ok && str.IsGlobal {
    63  		acceptable = true
    64  	}
    65  
    66  	if !acceptable {
    67  		return nil, false
    68  	}
    69  
    70  	// can simplify
    71  	p.UnsafeConvertValueToPointer[resolvedType] = true
    72  
    73  	return util.NewCallExpr(fmt.Sprintf("%s%s", unsafeConvertFunctionName,
    74  		typeToFuncname(resolvedType)),
    75  		util.NewUnaryExpr(goast.NewIdent(decl.Name), token.AND)), true
    76  }
    77  
    78  func typeToFuncname(typeName string) (functionName string) {
    79  	functionName = typeName
    80  	if index := strings.Index(functionName, "."); index > -1 {
    81  		functionName = functionName[index+1:]
    82  	}
    83  	return
    84  }
    85  
    86  func GetUnsafeConvertDecls(p *program.Program) {
    87  	if len(p.UnsafeConvertValueToPointer) == 0 {
    88  		return
    89  	}
    90  
    91  	p.AddImport("unsafe")
    92  
    93  	var names []string
    94  	for t := range p.UnsafeConvertValueToPointer {
    95  		names = append(names, t)
    96  	}
    97  	sort.Sort(sort.StringSlice(names))
    98  
    99  	for _, t := range names {
   100  		functionName := fmt.Sprintf("%s%s", unsafeConvertFunctionName,
   101  			typeToFuncname(t))
   102  		varName := "c4go_name"
   103  		p.File.Decls = append(p.File.Decls, &goast.FuncDecl{
   104  			Doc: &goast.CommentGroup{
   105  				List: []*goast.Comment{
   106  					{
   107  						Text: fmt.Sprintf("// %s : created by c4go\n", functionName),
   108  					},
   109  				},
   110  			},
   111  			Name: goast.NewIdent(functionName),
   112  			Type: &goast.FuncType{
   113  				Params: &goast.FieldList{
   114  					List: []*goast.Field{
   115  						{
   116  							Names: []*goast.Ident{goast.NewIdent(varName)},
   117  							Type:  goast.NewIdent("*" + t),
   118  						},
   119  					},
   120  				},
   121  				Results: &goast.FieldList{
   122  					List: []*goast.Field{
   123  						{
   124  							Type: &goast.ArrayType{
   125  								Lbrack: 1,
   126  								Elt:    goast.NewIdent(t),
   127  							},
   128  						},
   129  					},
   130  				},
   131  			},
   132  			Body: &goast.BlockStmt{
   133  				List: []goast.Stmt{
   134  					&goast.ReturnStmt{
   135  						Results: []goast.Expr{
   136  							&goast.SliceExpr{
   137  								X: util.NewCallExpr(fmt.Sprintf("(*[1000000]%s)", t),
   138  									util.NewCallExpr("unsafe.Pointer",
   139  										goast.NewIdent(varName)),
   140  								),
   141  							},
   142  						},
   143  					},
   144  				},
   145  			},
   146  		})
   147  	}
   148  
   149  	return
   150  }
   151  
   152  // ---------------- POINTER OPERATIONS ---------------------------------------
   153  // Examples:
   154  //	1) pointer + integer - integer
   155  //	2) pointer1 > pointer2
   156  //	3) pointer1 == pointer2
   157  //	4) pointer1 - pointer2
   158  //	5) pointer to integer address
   159  //	6) integer address to pointer
   160  //	7) pointerType1 to pointerType2
   161  //
   162  // Simplification:
   163  //	1) pointer +/- integer
   164  //	2) (pointer1 - pointer2) >  0
   165  //	3) (pointer1 - pointer2) == 0
   166  //	4) (pointer1 - pointer2)
   167  //	5) pointer to integer address
   168  //	6) integer address to pointer
   169  //	7) pointerType1 to integer address to pointerType2
   170  //
   171  
   172  // GetPointerAddress - return goast expression with pointer address.
   173  //
   174  //	pnt       - goast expression. Foe example: `&a`, `&a[11]`.
   175  //	sizeof    - sizeof of C type.
   176  //	rs        - result goast expression.
   177  //	postStmts - slice of goast.Stmt for runtime.KeepAlive of pointer,
   178  //	            the best way kept that stmts at the end of function.
   179  //	            Each stmt has `defer` functions.
   180  func GetPointerAddress(p *program.Program, expr goast.Expr, cType string, sizeof int) (
   181  	rs goast.Expr, postStmts []goast.Stmt, err error) {
   182  	defer func() {
   183  		if err != nil {
   184  			err = fmt.Errorf("GetPointerAddress:sizeof:%d. %v", sizeof, err)
   185  		}
   186  	}()
   187  
   188  	if expr == nil {
   189  		err = fmt.Errorf("cannot get pointer address for nil expr")
   190  		return
   191  	}
   192  
   193  	// if sizeof == 0 {
   194  	// 	err = fmt.Errorf("sizeof is zero")
   195  	// 	return
   196  	// }
   197  
   198  	// generate postStmts
   199  
   200  	// TODO: runtime.KeepAlive()
   201  
   202  	if par, ok := expr.(*goast.ParenExpr); ok {
   203  		// ignore parens
   204  		return GetPointerAddress(p, par.X, cType, sizeof)
   205  	}
   206  
   207  	if id, ok := expr.(*goast.Ident); ok {
   208  		if id.Name == "nil" {
   209  			// nil pointer
   210  			rs = goast.NewIdent("0")
   211  			return
   212  		}
   213  	}
   214  
   215  	isRealPointer := func() bool {
   216  		if cType == "FILE *" || cType == "struct _IO_FILE *" {
   217  			return true
   218  		}
   219  		return false
   220  	}
   221  
   222  	if _, ok := expr.(*goast.Ident); ok {
   223  		if !isRealPointer() {
   224  			expr = &goast.IndexExpr{
   225  				X:     expr,
   226  				Index: goast.NewIdent("0"),
   227  			}
   228  		}
   229  	}
   230  
   231  	if _, ok := expr.(*goast.SelectorExpr); ok {
   232  		expr = &goast.IndexExpr{
   233  			X:     expr,
   234  			Index: goast.NewIdent("0"),
   235  		}
   236  	}
   237  
   238  	if sl, ok := expr.(*goast.SliceExpr); ok {
   239  		// from :
   240  		//
   241  		// 88  0: *ast.SliceExpr {
   242  		// 89  .  X: *ast.Ident {
   243  		// 91  .  .  Name: "b"
   244  		// 93  .  }
   245  		// 95  .  Low: *ast.BasicLit { ... }
   246  		// 99  .  }
   247  		// 102  }
   248  		//
   249  		// to:
   250  		//
   251  		// 0  *ast.IndexExpr {
   252  		// 1  .  X: *ast.Ident {
   253  		// 3  .  .  Name: "b"
   254  		// 4  .  }
   255  		// 6  .  Index: *ast.BasicLit { ... }
   256  		// 12  }
   257  		if sl.Low == nil {
   258  			sl.Low = goast.NewIdent("0")
   259  		}
   260  		util.PanicIfNil(sl.X, "slice is nil")
   261  		util.PanicIfNil(sl.Low, "slice low is nil")
   262  		expr = &goast.IndexExpr{
   263  			X:     sl.X,
   264  			Index: sl.Low,
   265  		}
   266  	}
   267  
   268  	if sl, ok := expr.(*goast.SliceExpr); ok {
   269  		if c, ok := sl.X.(*goast.CallExpr); ok {
   270  			if fin, ok := c.Fun.(*goast.Ident); ok && strings.Contains(fin.Name, "1000000") {
   271  				if len(c.Args) == 1 {
   272  					if cc, ok := c.Args[0].(*goast.CallExpr); ok {
   273  						if fin, ok := cc.Fun.(*goast.Ident); ok && strings.Contains(fin.Name, "unsafe.Pointer") {
   274  							if len(cc.Args) == 1 {
   275  								if un, ok := cc.Args[0].(*goast.UnaryExpr); ok && un.Op == token.AND {
   276  									expr = un.X
   277  								}
   278  							}
   279  						}
   280  					}
   281  				}
   282  			}
   283  		}
   284  	}
   285  
   286  	if _, ok := expr.(*goast.CallExpr); ok {
   287  		name := "c4go_temp_name"
   288  		rs = util.NewAnonymousFunction(
   289  			// body
   290  			[]goast.Stmt{
   291  				&goast.ExprStmt{
   292  					X: &goast.BinaryExpr{
   293  						X:  goast.NewIdent(name),
   294  						Op: token.DEFINE,
   295  						Y:  expr,
   296  					},
   297  				},
   298  			},
   299  			// defer
   300  			nil,
   301  			// returnValue
   302  			util.NewCallExpr("int64", util.NewCallExpr("uintptr", util.NewCallExpr("unsafe.Pointer",
   303  				&goast.StarExpr{
   304  					Star: 1,
   305  					X: &goast.CallExpr{
   306  						Fun:    goast.NewIdent("(**byte)"),
   307  						Lparen: 1,
   308  						Args: []goast.Expr{&goast.CallExpr{
   309  							Fun:    goast.NewIdent("unsafe.Pointer"),
   310  							Lparen: 1,
   311  							Args: []goast.Expr{
   312  								util.NewUnaryExpr(goast.NewIdent(name), token.AND),
   313  							},
   314  						}},
   315  					},
   316  				},
   317  			))),
   318  			// returnType
   319  			"int64",
   320  		)
   321  		return
   322  	}
   323  
   324  	// prepare postStmts
   325  
   326  	if sizeof < 1 {
   327  		err = fmt.Errorf("not valid sizeof `%s`: %d", cType, sizeof)
   328  		p.AddMessage(p.GenerateWarningMessage(err, nil))
   329  		return
   330  	}
   331  
   332  	// main result expression
   333  	if !isRealPointer() {
   334  		rs = &goast.BinaryExpr{
   335  			X: util.NewCallExpr("int64", util.NewCallExpr("uintptr",
   336  				util.NewCallExpr("unsafe.Pointer",
   337  					util.NewUnaryExpr(expr, token.AND),
   338  				),
   339  			)),
   340  			Op: token.QUO,
   341  			Y:  util.NewCallExpr("int64", goast.NewIdent(fmt.Sprintf("%d", sizeof))),
   342  		}
   343  	} else {
   344  		rs = &goast.BinaryExpr{
   345  			X: util.NewCallExpr("int64", util.NewCallExpr("uintptr",
   346  				util.NewCallExpr("unsafe.Pointer",
   347  					expr,
   348  				),
   349  			)),
   350  			Op: token.QUO,
   351  			Y:  util.NewCallExpr("int64", goast.NewIdent(fmt.Sprintf("%d", sizeof))),
   352  		}
   353  	}
   354  
   355  	// return results
   356  	return
   357  }
   358  
   359  // SubTwoPnts function for implementation : (pointer1 - pointer2)
   360  func SubTwoPnts(
   361  	p *program.Program,
   362  	val1 goast.Expr, val1Type string,
   363  	val2 goast.Expr, val2Type string,
   364  	sizeof int) (rs goast.Expr, postStmts []goast.Stmt, err error) {
   365  	defer func() {
   366  		if err != nil {
   367  			err = fmt.Errorf("SubTwoPnts:%v", err)
   368  		}
   369  	}()
   370  
   371  	// if sizeof == 0 {
   372  	// 	err = fmt.Errorf("sizeof is zero")
   373  	// 	return
   374  	// }
   375  
   376  	x, newPost, err := GetPointerAddress(p, val1, val1Type, sizeof)
   377  	if err != nil {
   378  		return
   379  	}
   380  	postStmts = append(postStmts, newPost...)
   381  
   382  	y, newPost, err := GetPointerAddress(p, val2, val2Type, sizeof)
   383  	if err != nil {
   384  		return
   385  	}
   386  	postStmts = append(postStmts, newPost...)
   387  
   388  	rs = &goast.ParenExpr{X: &goast.BinaryExpr{X: x, Op: token.SUB, Y: y}}
   389  
   390  	return
   391  }
   392  
   393  // postStmts - slice of goast.Stmt for runtime.KeepAlive of pointer,
   394  //
   395  //	the best way kept that stmts at the end of function.
   396  //	Each stmt has `defer` functions.
   397  func PntCmpPnt(
   398  	p *program.Program,
   399  	val1 goast.Expr, val1Type string,
   400  	val2 goast.Expr, val2Type string,
   401  	sizeof int, operator token.Token,
   402  ) (
   403  	rs goast.Expr,
   404  	postStmts []goast.Stmt,
   405  	err error,
   406  ) {
   407  	defer func() {
   408  		if err != nil {
   409  			err = fmt.Errorf("PntCmpPnt:%v", err)
   410  		}
   411  	}()
   412  
   413  	// if sizeof == 0 {
   414  	// 	err = fmt.Errorf("sizeof is zero")
   415  	// 	return
   416  	// }
   417  
   418  	switch operator {
   419  	case token.SUB: // -
   420  		p.AddImport("unsafe")
   421  		sub, newPost, err := SubTwoPnts(p, val1, val1Type, val2, val2Type, sizeof)
   422  		postStmts = append(postStmts, newPost...)
   423  		return sub, postStmts, err
   424  	case token.LAND, token.LOR: // && ||
   425  		// TODO: add tests
   426  		p.AddImport("unsafe")
   427  		var newPost []goast.Stmt
   428  		val1, newPost, err = PntCmpPnt(
   429  			p,
   430  			val1, val1Type,
   431  			goast.NewIdent("nil"), types.NullPointer,
   432  			sizeof, token.EQL)
   433  		if err != nil {
   434  			return
   435  		}
   436  		postStmts = append(postStmts, newPost...)
   437  		val2, newPost, err = PntCmpPnt(
   438  			p,
   439  			val2, val2Type,
   440  			goast.NewIdent("nil"), types.NullPointer,
   441  			sizeof, token.EQL)
   442  		if err != nil {
   443  			return
   444  		}
   445  		postStmts = append(postStmts, newPost...)
   446  		rs = &goast.BinaryExpr{
   447  			X:  val1,
   448  			Op: operator,
   449  			Y:  val2,
   450  		}
   451  		return
   452  	}
   453  
   454  	// > >= > <= ==
   455  
   456  	{
   457  		// specific for operations with nil
   458  		isExprNil := func(node goast.Expr) bool {
   459  			id, ok := node.(*goast.Ident)
   460  			if !ok {
   461  				return false
   462  			}
   463  			if id.Name != "nil" {
   464  				return false
   465  			}
   466  			return true
   467  		}
   468  
   469  		if !(isExprNil(val1) && isExprNil(val2)) {
   470  			// Examples:
   471  			// val1 != nil
   472  			// val1 == nil
   473  			// val1  > nil
   474  			ignoreList := func(Type string) bool {
   475  				return util.IsFunction(Type) ||
   476  					Type == types.NullPointer ||
   477  					Type == "void *" ||
   478  					Type == "FILE *"
   479  			}
   480  
   481  			switch {
   482  			case isExprNil(val2):
   483  				if !ignoreList(val1Type) {
   484  					val1 = util.NewCallExpr("len", val1)
   485  					val2 = goast.NewIdent("0")
   486  				}
   487  				rs = &goast.BinaryExpr{
   488  					X:  val1,
   489  					Op: operator,
   490  					Y:  val2,
   491  				}
   492  				return
   493  
   494  			case isExprNil(val1):
   495  				if !ignoreList(val2Type) {
   496  					val1 = goast.NewIdent("0")
   497  					val2 = util.NewCallExpr("len", val2)
   498  				}
   499  				rs = &goast.BinaryExpr{
   500  					X:  val1,
   501  					Op: operator,
   502  					Y:  val2,
   503  				}
   504  				return
   505  			}
   506  		}
   507  	}
   508  
   509  	p.AddImport("unsafe")
   510  	sub, newPost, err := SubTwoPnts(p, val1, val1Type, val2, val2Type, sizeof)
   511  	postStmts = append(postStmts, newPost...)
   512  
   513  	rs = &goast.BinaryExpr{
   514  		X:  sub,
   515  		Op: operator,
   516  		Y:  goast.NewIdent("0"),
   517  	}
   518  
   519  	return
   520  }
   521  
   522  // PntBitCast - casting pointers
   523  func PntBitCast(expr goast.Expr, cFrom, cTo string, p *program.Program) (
   524  	rs goast.Expr, toCtype string, postStmts []goast.Stmt, err error) {
   525  	defer func() {
   526  		if err != nil {
   527  			err = fmt.Errorf("cannot PntBitCast : %v", err)
   528  			p.AddMessage(p.GenerateWarningMessage(err, nil))
   529  		}
   530  	}()
   531  
   532  	cFrom = util.GenerateCorrectType(cFrom)
   533  	cTo = util.GenerateCorrectType(cTo)
   534  	toCtype = cTo
   535  
   536  	if !types.IsPointer(cFrom, p) || !types.IsPointer(cTo, p) {
   537  		err = fmt.Errorf("some type is not pointer `%s` or `%s`", cFrom, cTo)
   538  		return
   539  	}
   540  
   541  	rs = expr
   542  
   543  	if cFrom == cTo {
   544  		// no need cast
   545  		return
   546  	}
   547  
   548  	if util.IsFunction(cFrom) {
   549  		return
   550  	}
   551  
   552  	// check typedef
   553  	{
   554  		typedefFromType := cFrom
   555  		typedefToType := cTo
   556  		for {
   557  			if t, ok := p.TypedefType[typedefFromType]; ok {
   558  				typedefFromType = t
   559  				continue
   560  			}
   561  			break
   562  		}
   563  		for {
   564  			if t, ok := p.TypedefType[typedefToType]; ok {
   565  				typedefToType = t
   566  				continue
   567  			}
   568  			break
   569  		}
   570  		if typedefFromType == typedefToType {
   571  			// no need cast
   572  			return
   573  		}
   574  	}
   575  
   576  	{
   577  		from, errf := types.ResolveType(p, cFrom)
   578  		to, errto := types.ResolveType(p, cTo)
   579  		if from == to && errf == nil && errto == nil {
   580  			// no need cast
   581  			return
   582  		}
   583  	}
   584  
   585  	if cTo == "void *" {
   586  		// no need cast
   587  		return
   588  	}
   589  
   590  	if cFrom == "void *" {
   591  		// no need cast
   592  		rs, err = types.CastExpr(p, expr, cFrom, cTo)
   593  		return
   594  	}
   595  
   596  	rs, postStmts, err = GetPointerAddress(p, expr, cFrom, 1)
   597  	if err != nil {
   598  		return
   599  	}
   600  	resolvedType, err := types.ResolveType(p, cTo)
   601  	if err != nil {
   602  		return
   603  	}
   604  
   605  	resolvedType = strings.Replace(resolvedType, "[]", "[1000000]", 1)
   606  
   607  	p.AddImport("unsafe")
   608  	rs = util.NewCallExpr("(*"+resolvedType+")", util.NewCallExpr("unsafe.Pointer",
   609  		util.NewCallExpr("uintptr", rs)))
   610  
   611  	rs = &goast.SliceExpr{
   612  		X:      rs,
   613  		Slice3: false,
   614  	}
   615  
   616  	return
   617  }
   618  
   619  // CreateSliceFromReference - create a slice, like :
   620  // (*[1]int)(unsafe.Pointer(&a))[:]
   621  func CreateSliceFromReference(goType string, expr goast.Expr) goast.Expr {
   622  	// If the Go type is blank it means that the C type is 'void'.
   623  	if goType == "" {
   624  		goType = "interface{}"
   625  	}
   626  
   627  	// This is a hack to convert a reference to a variable into a slice that
   628  	// points to the same location. It will look similar to:
   629  	//
   630  	//     (*[1]int)(unsafe.Pointer(&a))[:]
   631  	//
   632  	// You must always call this Go before using CreateSliceFromReference:
   633  	//
   634  	//     p.AddImport("unsafe")
   635  	//
   636  	return &goast.SliceExpr{
   637  		X: util.NewCallExpr(fmt.Sprintf("(*[1000000]%s)", goType),
   638  			util.NewCallExpr("unsafe.Pointer",
   639  				util.NewUnaryExpr(expr, token.AND)),
   640  		),
   641  	}
   642  }
   643  
   644  // pointerArithmetic - operations between 'int' and pointer
   645  // Example C code : ptr += i
   646  // ptr = (*(*[1]int)(unsafe.Pointer(uintptr(unsafe.Pointer(&ptr[0])) + (i)*unsafe.Sizeof(ptr[0]))))[:]
   647  // , where i  - right
   648  //
   649  //	  '+' - operator
   650  //	'ptr' - left
   651  //	'int' - leftType transpiled in Go type
   652  //
   653  // Note:
   654  // 1) rightType MUST be 'int'
   655  // 2) pointerArithmetic - implemented ONLY right part of formula
   656  // 3) right is MUST be positive value, because impossible multiply uintptr to (-1)
   657  func pointerArithmetic(p *program.Program,
   658  	left goast.Expr, leftType string,
   659  	right goast.Expr, rightType string,
   660  	operator token.Token) (
   661  	_ goast.Expr, _ string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
   662  	defer func() {
   663  		if err != nil {
   664  			err = fmt.Errorf("cannot transpile pointerArithmetic. err = %v", err)
   665  		}
   666  	}()
   667  
   668  	if operator == token.SUB {
   669  		right = &goast.UnaryExpr{
   670  			Op: token.SUB,
   671  			X:  right,
   672  		}
   673  		return pointerArithmetic(p, left, leftType, right, rightType, token.ADD)
   674  	}
   675  
   676  	if types.IsPointer(rightType, p) &&
   677  		(types.IsCInteger(p, leftType) || leftType == "bool") &&
   678  		operator == token.ADD {
   679  		// swap pointer operation
   680  		// from : integer + pnt
   681  		// to   : pnt + integer
   682  		return pointerArithmetic(p, right, rightType, left, leftType, operator)
   683  	}
   684  
   685  	// check input data
   686  	if !(types.IsCInteger(p, rightType) || rightType == "bool") {
   687  		err = fmt.Errorf("right type is not C integer type : '%s'", rightType)
   688  		return
   689  	}
   690  	if !types.IsPointer(leftType, p) {
   691  		err = fmt.Errorf("left type is not a pointer : '%s'", leftType)
   692  		return
   693  	}
   694  	right, err = types.CastExpr(p, right, rightType, "int")
   695  	if err != nil {
   696  		return
   697  	}
   698  
   699  	// prepare leftType - return base type
   700  	for {
   701  		if t, ok := p.TypedefType[leftType]; ok {
   702  			leftType = t
   703  			continue
   704  		}
   705  		break
   706  	}
   707  	resolvedLeftType, err := types.ResolveType(p, leftType)
   708  	if err != nil {
   709  		return
   710  	}
   711  
   712  	p.AddImport("unsafe")
   713  	p.AddImport("runtime")
   714  	p.AddImport("reflect")
   715  
   716  	// try use simplification for pointer arithmetic.
   717  	// typically used only for Go base types.
   718  	if strings.Count(resolvedLeftType, "[") > 0 {
   719  		shortType := types.GetBaseType(leftType)
   720  
   721  		var resolvedShortType string
   722  		resolvedShortType, err = types.ResolveType(p, shortType)
   723  		if err != nil {
   724  			return
   725  		}
   726  
   727  		var acceptable bool
   728  
   729  		if types.IsGoBaseType(resolvedShortType) {
   730  			acceptable = true
   731  		}
   732  
   733  		if str, ok := p.Structs[resolvedShortType]; ok && str.IsGlobal {
   734  			acceptable = true
   735  		}
   736  
   737  		if str, ok := p.Unions[resolvedShortType]; ok && str.IsGlobal {
   738  			acceptable = true
   739  		}
   740  
   741  		if acceptable {
   742  			// save for future generate code
   743  			p.UnsafeConvertPointerArith[resolvedLeftType] = true
   744  			return util.NewCallExpr(getFunctionPointerArith(resolvedLeftType), left, util.NewCallExpr("int", right)),
   745  				leftType, nil, nil, nil
   746  		}
   747  	}
   748  
   749  	type pA struct {
   750  		Name      string // name of variable: 'ptr'
   751  		Type      string // type of variable: 'int','double'
   752  		Condition string // condition : '-1' ,'(-1+2-2)'
   753  	}
   754  
   755  	var s pA
   756  
   757  	switch resolvedLeftType {
   758  	case "interface{}":
   759  		s.Type = "byte"
   760  	default:
   761  		s.Type = resolvedLeftType[2:]
   762  	}
   763  
   764  	{
   765  		var buf bytes.Buffer
   766  		_ = printer.Fprint(&buf, token.NewFileSet(), left)
   767  		s.Name = buf.String()
   768  	}
   769  	{
   770  		var buf bytes.Buffer
   771  		_ = printer.Fprint(&buf, token.NewFileSet(), right)
   772  		s.Condition = buf.String()
   773  	}
   774  
   775  	src := `package main
   776  func main(){
   777  	a := func()[]{{ .Type }} {
   778  		var position int32 = int32({{ .Condition }})
   779  		slice := {{ .Name }}
   780  		if position < 0 {
   781  			// invert sign
   782  			position = -position
   783  
   784  			// Example from: go101.org/article/unsafe.html	
   785  			var hdr reflect.SliceHeader
   786  			sliceLen := len(slice)
   787  			hdr.Data = uintptr(unsafe.Pointer(&slice[0])) - (uintptr(position))*unsafe.Sizeof(slice[0])
   788  			runtime.KeepAlive(&slice[0]) // needed!
   789  			hdr.Len = sliceLen + int(position)
   790  			hdr.Cap = hdr.Len
   791  			slice = *((*[]{{ .Type }})(unsafe.Pointer(&hdr)))
   792  			return slice
   793  		}
   794  		// position >= 0:
   795  		return slice[position:]
   796  	}()
   797  }`
   798  	tmpl := template.Must(template.New("").Parse(src))
   799  	var source bytes.Buffer
   800  	err = tmpl.Execute(&source, s)
   801  	if err != nil {
   802  		err = fmt.Errorf("cannot execute template. err = %v", err)
   803  		return
   804  	}
   805  
   806  	// Create the AST by parsing src.
   807  	fset := token.NewFileSet() // positions are relative to fset
   808  	body := strings.Replace(source.String(), "&#43;", "+", -1)
   809  	body = strings.Replace(body, "&amp;", "&", -1)
   810  	body = strings.Replace(body, "&#34;", "\"", -1)
   811  	body = strings.Replace(body, "&#39;", "'", -1)
   812  	body = strings.Replace(body, "&gt;", ">", -1)
   813  	body = strings.Replace(body, "&lt;", "<", -1)
   814  	// TODO: add unicode convertor
   815  	f, err := parser.ParseFile(fset, "", body, 0)
   816  	if err != nil {
   817  		body = strings.Replace(body, "\n", "", -1)
   818  		err = fmt.Errorf("cannot parse file. err = %v. body = `%s`", err, body)
   819  		return
   820  	}
   821  
   822  	return f.Decls[0].(*goast.FuncDecl).Body.List[0].(*goast.AssignStmt).Rhs[0],
   823  		leftType, preStmts, postStmts, nil
   824  }
   825  
   826  const unsafePointerArithFunctionName string = "c4goPointerArith"
   827  
   828  func getFunctionPointerArith(goType string) string {
   829  	return fmt.Sprintf("%s%s", unsafePointerArithFunctionName, util.GetExportedName(goType))
   830  }
   831  
   832  func pointerArithFunction(goType string) string {
   833  	return fmt.Sprintf(`
   834  
   835  // %s - function of pointer arithmetic. generated by c4go 
   836  func %s(slice %s, position int)%s {
   837  	if position < 0 {
   838  		// invert sign
   839  		position = -position
   840  
   841  		// Example from: go101.org/article/unsafe.html
   842  		// repair size of slice
   843  		var hdr reflect.SliceHeader
   844  		sliceLen := len(slice)
   845  		hdr.Data = uintptr(unsafe.Pointer(&slice[0])) - (uintptr(position))*unsafe.Sizeof(slice[0])
   846  		runtime.KeepAlive(&slice[0]) // needed!
   847  		hdr.Len = sliceLen + int(position)
   848  		hdr.Cap = hdr.Len
   849  		slice = *((*%s)(unsafe.Pointer(&hdr)))
   850  		return slice
   851  	}
   852  	// position >= 0:
   853  	return slice[position:]
   854  }
   855  
   856  `,
   857  		getFunctionPointerArith(goType),
   858  		getFunctionPointerArith(goType),
   859  		goType, goType, goType)
   860  
   861  }
   862  
   863  func getPointerArithFunctions(p *program.Program) (out string) {
   864  	for goType := range p.UnsafeConvertPointerArith {
   865  		out += pointerArithFunction(goType)
   866  	}
   867  	return
   868  }