github.com/gotranspile/cxgo@v0.3.8-0.20240118201721-29871598a6a2/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.IsUntypedInt() { 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), 10)) 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.IsUntypedInt() && ek.IsUntypedInt() { 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.IntType: 862 if from := e.Expr.CType(to); from.Kind().Is(types.UntypedFloat) { 863 return call(tp, call(ident("math.Floor"), e.Expr.AsExpr())) 864 } 865 case types.FloatType: 866 if from := e.Expr.CType(to); from.Kind().Is(types.UntypedInt) { 867 return e.Expr.AsExpr() 868 } 869 case types.PtrType: 870 if to.Elem() != nil { 871 switch et := e.Expr.CType(nil).(type) { 872 case types.IntType: 873 return call(paren(tp), call(unsafePtr(), call(ident("uintptr"), e.Expr.AsExpr()))) 874 case types.PtrType: 875 if et.Elem() != nil { 876 return call(paren(tp), call(unsafePtr(), e.Expr.AsExpr())) 877 } 878 } 879 } 880 } 881 if !isParenSafe(tp) { 882 tp = paren(tp) 883 } 884 return call(tp, e.Expr.AsExpr()) 885 } 886 887 func (e *CCastExpr) Uses() []types.Usage { 888 return types.UseRead(e.Expr) 889 } 890 891 type UnaryOp string 892 893 const ( 894 UnarySizeof UnaryOp = "sizeof" 895 896 UnaryPlus UnaryOp = "+" 897 UnaryMinus UnaryOp = "-" 898 UnaryXor UnaryOp = "^" 899 ) 900 901 func (g *translator) cSizeofE(x Expr) Expr { 902 switch t := types.Unwrap(x.CType(nil)).(type) { 903 case types.ArrayType: 904 if t.Len() <= 0 { 905 return g.newUnaryExpr(UnarySizeof, x) 906 } 907 } 908 switch cUnwrap(x).(type) { 909 case Bool: 910 case BoolExpr: 911 // workaround for C bools (they should be reported as int in some cases) 912 return g.SizeofT(g.env.DefIntT(), nil) 913 } 914 return g.SizeofT(x.CType(nil), nil) 915 } 916 917 func (g *translator) NewCUnaryExpr(op UnaryOp, x Expr) Expr { 918 switch op { 919 case UnarySizeof: 920 return g.cSizeofE(x) 921 case UnaryXor, UnaryMinus, UnaryPlus: 922 if xk := x.CType(nil).Kind(); xk.IsBool() { 923 x = g.cCast(g.env.DefIntT(), x) 924 } else if v, ok := x.(IntLit); ok && op == UnaryMinus { 925 return v.Negate() 926 } 927 } 928 return g.newUnaryExpr(op, x) 929 } 930 931 func (g *translator) NewCUnaryExprT(op UnaryOp, x Expr, typ types.Type) Expr { 932 if _, ok := x.(IntLit); ok && op == UnaryXor { 933 x = &CCastExpr{Expr: x, Type: typ} 934 } 935 x = g.NewCUnaryExpr(op, x) 936 if typ.Kind().IsBool() { 937 return x 938 } 939 if op == UnarySizeof { 940 return x 941 } 942 return g.cCast(typ, x) 943 } 944 945 func (g *translator) newUnaryExpr(op UnaryOp, x Expr) Expr { 946 return &CUnaryExpr{ 947 g: g, Op: op, Expr: x, 948 } 949 } 950 951 type CUnaryExpr struct { 952 g *translator 953 Op UnaryOp 954 Expr Expr 955 } 956 957 func (e *CUnaryExpr) Visit(v Visitor) { 958 v(e.Expr) 959 } 960 961 func (e *CUnaryExpr) CType(exp types.Type) types.Type { 962 switch e.Op { 963 case UnarySizeof: 964 return e.g.env.UintPtrT() 965 } 966 return e.Expr.CType(exp) 967 } 968 969 func (e *CUnaryExpr) IsConst() bool { 970 switch e.Op { 971 case UnaryPlus, UnaryMinus, UnaryXor: 972 return e.Expr.IsConst() 973 } 974 return false 975 } 976 977 func (e *CUnaryExpr) HasSideEffects() bool { 978 return e.Expr.HasSideEffects() 979 } 980 981 func (e *CUnaryExpr) AsExpr() GoExpr { 982 var tok token.Token 983 switch e.Op { 984 case UnarySizeof: 985 return call(e.CType(nil).GoType(), call(ident("unsafe.Sizeof"), e.Expr.AsExpr())) 986 case UnaryPlus: 987 tok = token.ADD 988 case UnaryMinus: 989 tok = token.SUB 990 case UnaryXor: 991 tok = token.XOR 992 default: 993 panic(e.Op) 994 } 995 return &ast.UnaryExpr{ 996 Op: tok, 997 X: e.Expr.AsExpr(), 998 } 999 } 1000 1001 func (e *CUnaryExpr) Uses() []types.Usage { 1002 return e.Expr.Uses() 1003 } 1004 1005 func (g *translator) SizeofT(t types.Type, typ types.Type) Expr { 1006 e := &CSizeofExpr{ 1007 rtyp: g.env.Go().Uintptr(), 1008 std: true, 1009 Type: t, 1010 } 1011 if typ != nil && typ != e.rtyp { 1012 if !typ.Kind().IsInt() { 1013 return g.cCast(typ, e) 1014 } 1015 e.rtyp = typ 1016 e.std = false 1017 } 1018 return e 1019 } 1020 1021 func (g *translator) AlignofT(t types.Type, typ types.Type) Expr { 1022 e := &CAlignofExpr{ 1023 rtyp: g.env.Go().Uintptr(), 1024 Type: t, 1025 } 1026 if typ != nil && typ != e.rtyp { 1027 if !typ.Kind().IsInt() { 1028 return g.cCast(typ, e) 1029 } 1030 e.rtyp = typ 1031 e.std = false 1032 } 1033 return e 1034 } 1035 1036 type CSizeofExpr struct { 1037 rtyp types.Type 1038 std bool 1039 Type types.Type 1040 } 1041 1042 func (e *CSizeofExpr) Visit(v Visitor) {} 1043 1044 func (e *CSizeofExpr) CType(types.Type) types.Type { 1045 return e.rtyp 1046 } 1047 1048 func (e *CSizeofExpr) IsConst() bool { 1049 return true 1050 } 1051 1052 func (e *CSizeofExpr) HasSideEffects() bool { 1053 return false 1054 } 1055 1056 func (e *CSizeofExpr) Uses() []types.Usage { 1057 // TODO: use type 1058 return nil 1059 } 1060 1061 func sizeOf(typ types.Type) GoExpr { 1062 switch typ := types.Unwrap(typ).(type) { 1063 case types.ArrayType: 1064 if !typ.IsSlice() && types.Unwrap(typ.Elem()) == types.UintT(1) { 1065 return intLit(typ.Len()) 1066 } 1067 } 1068 x := typ.GoType() 1069 switch types.Unwrap(typ).(type) { 1070 case *types.StructType, types.ArrayType: 1071 x = &ast.CompositeLit{Type: x} 1072 case types.PtrType: 1073 x = call(x, Nil{}.AsExpr()) 1074 case types.BoolType: 1075 x = call(x, boolLit(false)) 1076 case *types.FuncType: 1077 x = call(ident("uintptr"), intLit(0)) 1078 default: 1079 x = call(x, intLit(0)) 1080 } 1081 return call(ident("unsafe.Sizeof"), x) 1082 } 1083 1084 func (e *CSizeofExpr) AsExpr() GoExpr { 1085 x := sizeOf(e.Type) 1086 if !e.std { 1087 x = call(e.CType(nil).GoType(), x) 1088 } 1089 return x 1090 } 1091 1092 type CAlignofExpr struct { 1093 rtyp types.Type 1094 std bool 1095 Type types.Type 1096 } 1097 1098 func (e *CAlignofExpr) Visit(v Visitor) {} 1099 1100 func (e *CAlignofExpr) CType(types.Type) types.Type { 1101 return e.rtyp 1102 } 1103 1104 func (e *CAlignofExpr) IsConst() bool { 1105 return true 1106 } 1107 1108 func (e *CAlignofExpr) HasSideEffects() bool { 1109 return false 1110 } 1111 1112 func (e *CAlignofExpr) Uses() []types.Usage { 1113 // TODO: use type 1114 return nil 1115 } 1116 1117 func zeroOf(typ types.Type) GoExpr { 1118 x := typ.GoType() 1119 switch types.Unwrap(typ).(type) { 1120 case *types.StructType, types.ArrayType: 1121 x = &ast.CompositeLit{Type: x} 1122 case types.PtrType: 1123 x = call(x, Nil{}.AsExpr()) 1124 case types.BoolType: 1125 x = call(x, boolLit(false)) 1126 default: 1127 x = call(x, intLit(0)) 1128 } 1129 return x 1130 } 1131 1132 func (e *CAlignofExpr) AsExpr() GoExpr { 1133 x := call(ident("unsafe.Alignof"), zeroOf(e.Type)) 1134 if !e.std { 1135 x = call(e.CType(nil).GoType(), x) 1136 } 1137 return x 1138 } 1139 1140 var _ CStmtConv = &CAssignExpr{} 1141 1142 func (g *translator) NewCAssignExpr(x Expr, op BinaryOp, y Expr) Expr { 1143 return &CAssignExpr{ 1144 Stmt: g.NewCAssignStmtP(x, op, y), 1145 } 1146 } 1147 1148 type CAssignExpr struct { 1149 Stmt *CAssignStmt 1150 } 1151 1152 func (e *CAssignExpr) Visit(v Visitor) { 1153 v(e.Stmt) 1154 } 1155 1156 func (e *CAssignExpr) CType(types.Type) types.Type { 1157 return e.Stmt.Left.CType(nil) 1158 } 1159 1160 func (e *CAssignExpr) IsConst() bool { 1161 return false 1162 } 1163 1164 func (e *CAssignExpr) HasSideEffects() bool { 1165 return true 1166 } 1167 1168 func (e *CAssignExpr) ToStmt() []CStmt { 1169 return e.Stmt.g.NewCAssignStmt(e.Stmt.Left, e.Stmt.Op, e.Stmt.Right) 1170 } 1171 1172 func (e *CAssignExpr) AsExpr() GoExpr { 1173 ret := e.CType(nil) 1174 var stmts []GoStmt 1175 if id, ok := e.Stmt.Left.(IdentExpr); ok { 1176 stmts = append(stmts, 1177 e.Stmt.g.NewCAssignStmtP(id, e.Stmt.Op, e.Stmt.Right).AsStmt()..., 1178 ) 1179 stmts = append(stmts, 1180 returnStmt(id.GoIdent()), 1181 ) 1182 return callLambda( 1183 ret.GoType(), 1184 stmts..., 1185 ) 1186 } 1187 x, y := &TakeAddr{g: e.Stmt.g, X: e.Stmt.Left}, e.Stmt.Right 1188 p := types.NewIdent("p", x.CType(nil)) 1189 pg := p.GoIdent() 1190 stmts = append(stmts, 1191 define(pg, x.AsExpr()), 1192 ) 1193 stmts = append(stmts, 1194 e.Stmt.g.NewCAssignStmtP(e.Stmt.g.cDeref(x), e.Stmt.Op, y).AsStmt()..., 1195 ) 1196 stmts = append(stmts, 1197 returnStmt(deref(pg)), 1198 ) 1199 return callLambda( 1200 ret.GoType(), 1201 stmts..., 1202 ) 1203 } 1204 1205 func (e *CAssignExpr) Uses() []types.Usage { 1206 var list []types.Usage 1207 list = append(list, types.UseRead(e.Stmt.Left)...) 1208 list = append(list, types.UseWrite(e.Stmt.Left)...) 1209 list = append(list, types.UseRead(e.Stmt.Right)...) 1210 return list 1211 } 1212 1213 func mergeStructInitializers(items []*CompLitField) []*CompLitField { 1214 out := make([]*CompLitField, 0, len(items)) 1215 byField := make(map[string]*CompLitField) 1216 for _, it := range items { 1217 if it.Field == nil { 1218 out = append(out, it) 1219 continue 1220 } 1221 c1, ok := cUnwrap(it.Value).(*CCompLitExpr) 1222 if !ok { 1223 out = append(out, it) 1224 continue 1225 } 1226 it2 := byField[it.Field.Name] 1227 if it2 == nil { 1228 byField[it.Field.Name] = it 1229 out = append(out, it) 1230 continue 1231 } 1232 c2, ok := cUnwrap(it2.Value).(*CCompLitExpr) 1233 if !ok { 1234 out = append(out, it) 1235 continue 1236 } 1237 if !types.Same(c1.Type, c2.Type) { 1238 out = append(out, it) 1239 continue 1240 } 1241 sub := make([]*CompLitField, 0, len(c1.Fields)+len(c2.Fields)) 1242 sub = append(sub, c2.Fields...) 1243 sub = append(sub, c1.Fields...) 1244 c2.Fields = sub 1245 } 1246 return out 1247 } 1248 1249 func (g *translator) NewCCompLitExpr(typ types.Type, items []*CompLitField) Expr { 1250 if k := typ.Kind(); k.Is(types.Struct) { 1251 st := types.Unwrap(typ).(*types.StructType) 1252 next := 0 1253 for _, it := range items { 1254 var ft types.Type 1255 if it.Field != nil { 1256 ft = it.Field.CType(nil) 1257 } else if it.Index == nil { 1258 f := st.Fields()[next] 1259 next++ 1260 it.Field = f.Name 1261 ft = f.Type() 1262 } else if l, ok := cUnwrap(it.Index).(IntLit); ok { 1263 next = int(l.Uint()) 1264 f := st.Fields()[next] 1265 next++ 1266 it.Field = f.Name 1267 ft = f.Type() 1268 } 1269 if ft != nil { 1270 it.Value = g.cCast(ft, it.Value) 1271 } 1272 } 1273 items = mergeStructInitializers(items) 1274 } else if k.Is(types.Array) { 1275 arr := types.Unwrap(typ).(types.ArrayType) 1276 tp := arr.Elem() 1277 for _, it := range items { 1278 it.Value = g.cCast(tp, it.Value) 1279 } 1280 } 1281 return &CCompLitExpr{Type: typ, Fields: items} 1282 } 1283 1284 type CompLitField struct { 1285 Index Expr 1286 Field *types.Ident 1287 Value Expr 1288 } 1289 1290 func (e *CompLitField) Visit(v Visitor) { 1291 v(e.Index) 1292 if e.Field != nil { 1293 v(IdentExpr{e.Field}) 1294 } 1295 v(e.Value) 1296 } 1297 1298 type CCompLitExpr struct { 1299 Type types.Type 1300 Fields []*CompLitField 1301 } 1302 1303 func (e *CCompLitExpr) Visit(v Visitor) { 1304 for _, f := range e.Fields { 1305 v(f) 1306 } 1307 } 1308 1309 func (e *CCompLitExpr) CType(types.Type) types.Type { 1310 return e.Type 1311 } 1312 1313 func (e *CCompLitExpr) IsConst() bool { 1314 return false 1315 } 1316 1317 func (e *CCompLitExpr) HasSideEffects() bool { 1318 has := false 1319 for _, f := range e.Fields { 1320 has = has || f.Value.HasSideEffects() 1321 } 1322 return has 1323 } 1324 1325 func (e *CCompLitExpr) isZero() bool { 1326 for _, f := range e.Fields { 1327 switch v := cUnwrapConst(f.Value).(type) { 1328 case IntLit: 1329 if !v.IsZero() { 1330 return false 1331 } 1332 case Nil: 1333 // nop 1334 case *CCompLitExpr: 1335 if !v.isZero() { 1336 return false 1337 } 1338 default: 1339 return false 1340 } 1341 } 1342 return true 1343 } 1344 1345 func (e *CCompLitExpr) AsExpr() GoExpr { 1346 if e.isZero() { 1347 // special case: MyStruct{0} usually means the same in C as MyStruct{} in Go 1348 return &ast.CompositeLit{ 1349 Type: e.Type.GoType(), 1350 } 1351 } 1352 var items []GoExpr 1353 isArr := e.CType(nil).Kind().Is(types.Array) 1354 ordered := false 1355 if isArr { 1356 // check if array elements are ordered so we can skip indexes in the init 1357 at, ok := types.Unwrap(e.CType(nil)).(types.ArrayType) 1358 if ok && at.Len() == len(e.Fields) { 1359 ordered = true 1360 for i, f := range e.Fields { 1361 if f.Index == nil { 1362 continue 1363 } 1364 v, ok := cUnwrap(f.Index).(IntLit) 1365 if !ok { 1366 ordered = false 1367 break 1368 } 1369 if !v.IsUint() || i != int(v.Uint()) { 1370 ordered = false 1371 break 1372 } 1373 } 1374 } 1375 } 1376 for _, f := range e.Fields { 1377 v := f.Value.AsExpr() 1378 if v, ok := v.(*ast.CompositeLit); ok && isArr { 1379 v.Type = nil 1380 } 1381 if f.Field != nil { 1382 items = append(items, &ast.KeyValueExpr{ 1383 Key: f.Field.GoIdent(), 1384 Value: v, 1385 }) 1386 } else if f.Index != nil && !ordered { 1387 items = append(items, &ast.KeyValueExpr{ 1388 Key: f.Index.AsExpr(), 1389 Value: v, 1390 }) 1391 } else { 1392 items = append(items, v) 1393 } 1394 } 1395 return &ast.CompositeLit{ 1396 Type: e.Type.GoType(), 1397 Elts: items, 1398 } 1399 } 1400 1401 func (e *CCompLitExpr) Uses() []types.Usage { 1402 var list []types.Usage 1403 // TODO: use the type 1404 for _, e := range e.Fields { 1405 if e.Field != nil { 1406 list = append(list, types.Usage{Ident: e.Field, Access: types.AccessWrite}) 1407 } 1408 if e.Value != nil { 1409 list = append(list, types.UseRead(e.Value)...) 1410 } 1411 if e.Index != nil { 1412 list = append(list, types.UseRead(e.Index)...) 1413 } 1414 } 1415 return list 1416 } 1417 1418 type TypeAssert struct { 1419 Type types.Type 1420 Expr Expr 1421 } 1422 1423 func (e *TypeAssert) IsConst() bool { 1424 return false 1425 } 1426 1427 func (e *TypeAssert) HasSideEffects() bool { 1428 return true 1429 } 1430 1431 func (e *TypeAssert) CType(types.Type) types.Type { 1432 return e.Type 1433 } 1434 1435 func (e *TypeAssert) AsExpr() GoExpr { 1436 return &ast.TypeAssertExpr{ 1437 X: e.Expr.AsExpr(), 1438 Type: e.Type.GoType(), 1439 } 1440 } 1441 1442 type SliceExpr struct { 1443 Expr Expr 1444 Low Expr 1445 High Expr 1446 Max Expr 1447 Slice3 bool 1448 } 1449 1450 func (e *SliceExpr) Visit(v Visitor) { 1451 v(e.Expr) 1452 } 1453 1454 func (e *SliceExpr) IsConst() bool { 1455 return false 1456 } 1457 1458 func (e *SliceExpr) HasSideEffects() bool { 1459 return false 1460 } 1461 1462 func (e *SliceExpr) CType(exp types.Type) types.Type { 1463 return e.Expr.CType(exp) 1464 } 1465 1466 func (e *SliceExpr) AsExpr() GoExpr { 1467 var low, high, max GoExpr 1468 if e.Low != nil { 1469 low = e.Low.AsExpr() 1470 } 1471 if e.High != nil { 1472 high = e.High.AsExpr() 1473 } 1474 if e.Max != nil { 1475 max = e.Max.AsExpr() 1476 } 1477 return &ast.SliceExpr{ 1478 X: e.Expr.AsExpr(), 1479 Low: low, High: high, Max: max, 1480 Slice3: e.Slice3, 1481 } 1482 } 1483 1484 func (e *SliceExpr) Uses() []types.Usage { 1485 uses := e.Expr.Uses() 1486 uses = append(uses, types.UseRead(e.Low, e.High, e.Max)...) 1487 return uses 1488 } 1489 1490 func exprCost(e Expr) int { 1491 if e == nil { 1492 return 0 1493 } 1494 switch e := e.(type) { 1495 case *CMultiExpr: 1496 c := 0 1497 for _, s := range e.Exprs { 1498 c += exprCost(s) 1499 } 1500 return c 1501 case *CallExpr: 1502 c := 1 1503 for _, s := range e.Args { 1504 c += exprCost(s) 1505 } 1506 return c 1507 case *CTernaryExpr: 1508 return 1 + exprCost(e.Cond) + exprCost(e.Then) + exprCost(e.Else) 1509 case *CAssignExpr: 1510 return 1 + stmtCost(e.Stmt) 1511 case *CBinaryExpr: 1512 return 1 + exprCost(e.Left) + exprCost(e.Right) 1513 case *CIndexExpr: 1514 return 1 + exprCost(e.Expr) + exprCost(e.Index) 1515 case *CSelectExpr: 1516 return 1 + exprCost(e.Expr) 1517 case *CCastExpr: 1518 return 1 + exprCost(e.Expr) 1519 case *CIncrExpr: 1520 return 1 + exprCost(e.Expr) 1521 case *CUnaryExpr: 1522 return 1 + exprCost(e.Expr) 1523 case *CParentExpr: 1524 return exprCost(e.Expr) 1525 default: 1526 return 1 1527 } 1528 }