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