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(), "+", "+", -1) 809 body = strings.Replace(body, "&", "&", -1) 810 body = strings.Replace(body, """, "\"", -1) 811 body = strings.Replace(body, "'", "'", -1) 812 body = strings.Replace(body, ">", ">", -1) 813 body = strings.Replace(body, "<", "<", -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 }