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