github.com/gotranspile/cxgo@v0.3.7/funcs.go (about) 1 package cxgo 2 3 import ( 4 "fmt" 5 "go/ast" 6 7 "github.com/gotranspile/cxgo/types" 8 ) 9 10 func ToFuncExpr(exp types.Type) *types.FuncType { 11 if t, ok := exp.(types.PtrType); ok { 12 exp = t.Elem() 13 } 14 if t, ok := types.Unwrap(exp).(*types.FuncType); ok { 15 return t 16 } 17 return nil 18 } 19 20 var _ FuncExpr = Nil{} 21 22 // FuncExpr is an expression that returns a function value. 23 type FuncExpr interface { 24 Expr 25 // FuncType return an underlying function type. 26 FuncType(exp *types.FuncType) *types.FuncType 27 } 28 29 var ( 30 _ FuncExpr = FuncIdent{} 31 _ Ident = FuncIdent{} 32 ) 33 34 type FuncIdent struct { 35 *types.Ident 36 } 37 38 func (FuncIdent) Visit(v Visitor) {} 39 40 func (e FuncIdent) Identifier() *types.Ident { 41 return e.Ident 42 } 43 44 func (e FuncIdent) IsConst() bool { 45 return false 46 } 47 48 func (e FuncIdent) HasSideEffects() bool { 49 return false 50 } 51 52 func (e FuncIdent) AsExpr() GoExpr { 53 return e.GoIdent() 54 } 55 56 func (e FuncIdent) FuncType(exp *types.FuncType) *types.FuncType { 57 var et types.Type 58 if exp != nil { 59 et = exp 60 } 61 return types.Unwrap(e.CType(et)).(*types.FuncType) 62 } 63 64 func (e FuncIdent) Uses() []types.Usage { 65 return []types.Usage{{Ident: e.Ident, Access: types.AccessUnknown}} 66 } 67 68 var _ FuncExpr = FuncAssert{} 69 70 type FuncAssert struct { 71 X Expr 72 } 73 74 func (e FuncAssert) Visit(v Visitor) { 75 v(e.X) 76 } 77 78 func (e FuncAssert) CType(types.Type) types.Type { 79 return e.X.CType(nil) 80 } 81 82 func (e FuncAssert) IsConst() bool { 83 return e.X.IsConst() 84 } 85 86 func (e FuncAssert) HasSideEffects() bool { 87 return e.X.HasSideEffects() 88 } 89 90 func (e FuncAssert) AsExpr() GoExpr { 91 return e.X.AsExpr() 92 } 93 94 func (e FuncAssert) FuncType(*types.FuncType) *types.FuncType { 95 return types.Unwrap(e.CType(nil)).(*types.FuncType) 96 } 97 98 func (e FuncAssert) Uses() []types.Usage { 99 return e.X.Uses() 100 } 101 102 func asSizeofT(e Expr) types.Type { 103 e = unwrapCasts(e) 104 sz, ok := e.(*CSizeofExpr) 105 if !ok { 106 return nil 107 } 108 return sz.Type 109 } 110 111 func (g *translator) NewCCallExpr(fnc FuncExpr, args []Expr) Expr { 112 if id, ok := cUnwrap(fnc).(IdentExpr); ok { 113 // TODO: another way to hook into it? 114 switch id.Ident { 115 case g.env.C().AssertFunc(): 116 // assert(!const) -> panic(const) 117 if len(args) == 1 { 118 a1 := args[0] 119 if a1.IsConst() { 120 if IsNil(a1) { 121 return &CallExpr{ 122 Fun: FuncIdent{g.env.Go().PanicFunc()}, 123 Args: []Expr{a1}, 124 } 125 } 126 switch a1 := a1.(type) { 127 case *Not: 128 return &CallExpr{ 129 Fun: FuncIdent{g.env.Go().PanicFunc()}, 130 Args: []Expr{unwrapCasts(a1.X)}, 131 } 132 case *Comparison: 133 switch a1.Op { 134 case BinOpEq: 135 if !IsNil(a1.X) && IsNil(a1.Y) { 136 return &CallExpr{ 137 Fun: FuncIdent{g.env.Go().PanicFunc()}, 138 Args: []Expr{unwrapCasts(a1.X)}, 139 } 140 } 141 } 142 case *PtrComparison: 143 switch a1.Op { 144 case BinOpEq: 145 if !IsNil(a1.X) && IsNil(a1.Y) { 146 return &CallExpr{ 147 Fun: FuncIdent{g.env.Go().PanicFunc()}, 148 Args: []Expr{unwrapCasts(a1.X)}, 149 } 150 } 151 } 152 } 153 } 154 return &CallExpr{ 155 Fun: FuncIdent{g.env.C().AssertFunc()}, 156 Args: []Expr{g.ToBool(a1)}, 157 } 158 } 159 case g.env.C().MallocFunc(): 160 // malloc(sizeof(T)) -> new(T) 161 if len(args) == 1 { 162 if tp := asSizeofT(args[0]); tp != nil { 163 return &NewExpr{ 164 e: g.env.Env, 165 Elem: tp, 166 } 167 } 168 } 169 case g.env.C().CallocFunc(): 170 // calloc(n, sizeof(T)) -> make([]T, n) 171 if len(args) == 2 { 172 if tp := asSizeofT(args[1]); tp != nil { 173 return &MakeExpr{ 174 e: g.env.Env, 175 Elem: tp, 176 Size: g.cCast(g.env.Go().Int(), args[0]), 177 } 178 } 179 } 180 case g.env.C().MemsetFunc(): 181 // memset(p, 0, sizeof(T)) -> *p = T{} 182 if len(args) == 3 { 183 if lit, ok := unwrapCasts(args[1]).(IntLit); ok && lit.IsZero() { 184 if tp := asSizeofT(args[2]); tp != nil { 185 p := g.cDeref(g.ToPointer(g.cCast(g.env.PtrT(tp), args[0]))) 186 return g.NewCAssignExpr(p, "", g.ZeroValue(tp)) 187 } 188 } 189 } 190 case g.env.C().StrdupFunc(): 191 // strdup(string) -> string 192 if len(args) == 1 { 193 if args[0].CType(nil) == g.env.Go().String() { 194 return args[0] 195 } 196 } 197 case g.env.C().StrndupFunc(): 198 // strndup(string, n) -> string[:n] 199 if len(args) == 2 { 200 if args[0].CType(nil) == g.env.Go().String() { 201 return &SliceExpr{Expr: args[0], High: args[1]} 202 } 203 } 204 case g.env.Go().SliceFunc(): 205 // _slice(arr, -1, 1) -> arr[:1] 206 if len(args) == 3 || len(args) == 4 { 207 var low, high, max Expr 208 if i, ok := args[1].(Number); !ok || !i.IsNegative() { 209 low = args[1] 210 } 211 if i, ok := args[2].(Number); !ok || !i.IsNegative() { 212 high = args[2] 213 } 214 if len(args) > 3 { 215 if i, ok := args[3].(Number); !ok || !i.IsNegative() { 216 max = args[3] 217 } 218 } 219 return &SliceExpr{ 220 Expr: args[0], 221 Low: low, High: high, Max: max, 222 Slice3: len(args) > 3, 223 } 224 } 225 case g.env.Go().MakeFunc(): 226 if len(args) == 2 || len(args) == 3 { 227 if arr, ok := args[0].CType(nil).(types.ArrayType); ok { 228 var a3 Expr 229 if len(args) > 2 { 230 a3 = args[2] 231 } 232 return &MakeExpr{ 233 e: g.env.Env, 234 Elem: arr.Elem(), 235 Size: args[1], 236 Cap: a3, 237 } 238 } 239 } 240 case g.env.Go().AppendFunc(): 241 if len(args) == 2 { 242 xt, yt := args[0].CType(nil), args[1].CType(nil) 243 if xt.Kind() == types.Array && yt.Kind() == types.Array { 244 args[1] = &ExpandExpr{X: args[1]} 245 return &CallExpr{ 246 Fun: fnc, 247 Args: args, 248 } 249 } 250 } 251 } 252 // kf, ok := knownCFuncs[id.Name] 253 // if !ok { 254 // kf, ok = known[id.Ident] 255 // } 256 // if ok && (id.Ident != kf.Name || (kf.This != nil && len(args) > len(kf.This.Args))) { 257 // if kf.This == nil { 258 // return NewCCallExpr(IdentExpr{kf.Name}, args) 259 // } 260 // fnc = &CSelectExpr{ 261 // ctype: kf.This, 262 // Expr: cCast(kf.Type.Args[0].Type, args[0]), 263 // Sel: kf.Name, 264 // } 265 // return NewCCallExpr(fnc, args[1:]) 266 // } 267 } 268 t := fnc.CType(nil) 269 if p, ok := t.(types.PtrType); ok && p.Elem() != nil { 270 t = p.Elem() 271 } 272 ft := types.Unwrap(t).(*types.FuncType) 273 ftargs := ft.Args() 274 for i, a := range args { 275 var atyp types.Type 276 if i < len(ftargs) { 277 atyp = ftargs[i].Type() 278 } else if ft.Variadic() { 279 atyp = types.UnkT(1) 280 } else { 281 break 282 } 283 args[i] = g.cCast(atyp, a) 284 } 285 return &CallExpr{ 286 Fun: fnc, 287 Args: args, 288 } 289 } 290 291 var _ Expr = (*CallExpr)(nil) 292 293 type CallExpr struct { 294 Fun FuncExpr 295 Args []Expr 296 } 297 298 func (e *CallExpr) Visit(v Visitor) { 299 v(e.Fun) 300 for _, a := range e.Args { 301 v(a) 302 } 303 } 304 305 func (e *CallExpr) CType(types.Type) types.Type { 306 typ := e.Fun.FuncType(nil) 307 if typ.Return() == nil { 308 panic("function doesn't return") 309 } 310 return typ.Return() 311 } 312 313 func (e *CallExpr) IsConst() bool { 314 return false 315 } 316 317 func (e *CallExpr) HasSideEffects() bool { 318 return true 319 } 320 321 func (e *CallExpr) AsExpr() GoExpr { 322 var args []GoExpr 323 vari := false 324 for _, a := range e.Args { 325 if x, ok := a.(*ExpandExpr); ok { 326 vari = true 327 a = x.X 328 } 329 args = append(args, a.AsExpr()) 330 } 331 if vari { 332 return callVari(e.Fun.AsExpr(), args...) 333 } 334 return call(e.Fun.AsExpr(), args...) 335 } 336 337 func (e *CallExpr) Uses() []types.Usage { 338 var list []types.Usage 339 list = append(list, types.UseRead(e.Fun)...) 340 for _, a := range e.Args { 341 list = append(list, types.UseRead(a)...) 342 } 343 return list 344 } 345 346 var _ FuncExpr = (*FuncLit)(nil) 347 348 func (g *translator) NewFuncLit(typ *types.FuncType, body ...CStmt) *FuncLit { 349 if typ.Return() != nil && typ.Return().Kind().IsUntyped() { 350 panic("untyped") 351 } 352 return &FuncLit{ 353 Type: typ, 354 Body: g.NewCBlock(body...), 355 } 356 } 357 358 type FuncLit struct { 359 Type *types.FuncType 360 Body *BlockStmt 361 } 362 363 func (e *FuncLit) Visit(v Visitor) { 364 v(e.Body) 365 } 366 367 func (e *FuncLit) IsConst() bool { 368 return false 369 } 370 371 func (e *FuncLit) HasSideEffects() bool { 372 return true 373 } 374 375 func (e *FuncLit) CType(types.Type) types.Type { 376 return e.Type 377 } 378 379 func (e *FuncLit) FuncType(*types.FuncType) *types.FuncType { 380 return e.Type 381 } 382 383 func (e *FuncLit) AsExpr() GoExpr { 384 return &ast.FuncLit{ 385 Type: e.Type.GoFuncType(), 386 Body: e.Body.GoBlockStmt(), 387 } 388 } 389 390 func (e *FuncLit) Uses() []types.Usage { 391 var list []types.Usage 392 // TODO: use the type 393 if e.Body != nil { 394 list = append(list, e.Body.Uses()...) 395 } 396 return list 397 } 398 399 var _ FuncExpr = (*PtrToFunc)(nil) 400 401 type PtrToFunc struct { 402 X PtrExpr 403 To *types.FuncType 404 } 405 406 func (e *PtrToFunc) Visit(v Visitor) { 407 v(e.X) 408 } 409 410 func (e *PtrToFunc) CType(types.Type) types.Type { 411 return e.To 412 } 413 414 func (e *PtrToFunc) AsExpr() GoExpr { 415 x := e.X.AsExpr() 416 ft := e.To.GoType() 417 asFunc := call( 418 ident("libc.AsFunc"), x, 419 call(paren(deref(ft)), ident("nil")), 420 ) 421 return typAssert(asFunc, ft) 422 } 423 424 func (e *PtrToFunc) IsConst() bool { 425 return false 426 } 427 428 func (e *PtrToFunc) HasSideEffects() bool { 429 return e.X.HasSideEffects() 430 } 431 432 func (e *PtrToFunc) Uses() []types.Usage { 433 return e.X.Uses() 434 } 435 436 func (e *PtrToFunc) FuncType(*types.FuncType) *types.FuncType { 437 return e.To 438 } 439 440 var _ PtrExpr = (*FuncToPtr)(nil) 441 442 type FuncToPtr struct { 443 e *types.Env 444 X FuncExpr 445 } 446 447 func (e *FuncToPtr) Visit(v Visitor) { 448 v(e.X) 449 } 450 451 func (e *FuncToPtr) CType(types.Type) types.Type { 452 return e.PtrType(nil) 453 } 454 455 func (e *FuncToPtr) AsExpr() GoExpr { 456 x := e.X.AsExpr() 457 return call(unsafePtr(), call(ident("libc.FuncAddr"), x)) 458 } 459 460 func (e *FuncToPtr) IsConst() bool { 461 return false 462 } 463 464 func (e *FuncToPtr) HasSideEffects() bool { 465 return e.X.HasSideEffects() 466 } 467 468 func (e *FuncToPtr) Uses() []types.Usage { 469 return e.X.Uses() 470 } 471 472 func (e *FuncToPtr) PtrType(types.PtrType) types.PtrType { 473 return e.e.PtrT(nil) 474 } 475 476 var _ FuncExpr = (*IntToFunc)(nil) 477 478 type IntToFunc struct { 479 X Expr 480 To *types.FuncType 481 } 482 483 func (e *IntToFunc) Visit(v Visitor) { 484 v(e.X) 485 } 486 487 func (e *IntToFunc) CType(types.Type) types.Type { 488 return e.To 489 } 490 491 func (e *IntToFunc) AsExpr() GoExpr { 492 x := e.X.AsExpr() 493 ft := e.To.GoType() 494 asFunc := call( 495 ident("libc.AsFunc"), x, 496 call(paren(deref(ft)), ident("nil")), 497 ) 498 return typAssert(asFunc, ft) 499 } 500 501 func (e *IntToFunc) IsConst() bool { 502 return false 503 } 504 505 func (e *IntToFunc) HasSideEffects() bool { 506 return e.X.HasSideEffects() 507 } 508 509 func (e *IntToFunc) Uses() []types.Usage { 510 return e.X.Uses() 511 } 512 513 func (e *IntToFunc) FuncType(*types.FuncType) *types.FuncType { 514 return e.To 515 } 516 517 var _ Expr = (*FuncToInt)(nil) 518 519 type FuncToInt struct { 520 X FuncExpr 521 To types.IntType 522 } 523 524 func (e *FuncToInt) Visit(v Visitor) { 525 v(e.X) 526 } 527 528 func (e *FuncToInt) CType(types.Type) types.Type { 529 return e.To 530 } 531 532 func (e *FuncToInt) AsExpr() GoExpr { 533 x := e.X.AsExpr() 534 x = call(ident("libc.FuncAddr"), x) 535 x = call(e.To.GoType(), x) 536 return x 537 } 538 539 func (e *FuncToInt) IsConst() bool { 540 return false 541 } 542 543 func (e *FuncToInt) HasSideEffects() bool { 544 return e.X.HasSideEffects() 545 } 546 547 func (e *FuncToInt) Uses() []types.Usage { 548 return e.X.Uses() 549 } 550 551 func (g *translator) ToFunc(x Expr, exp *types.FuncType) FuncExpr { 552 if x, ok := x.(FuncExpr); ok { 553 return x 554 } 555 if x, ok := cUnwrap(x).(IntLit); ok && x.IsZero() { 556 return g.Nil() 557 } 558 xt := x.CType(nil) 559 xk := xt.Kind() 560 if xk.IsFunc() { 561 switch x := x.(type) { 562 case Ident: 563 return FuncIdent{x.Identifier()} 564 } 565 return FuncAssert{x} 566 } 567 if xk.IsPtr() { 568 if exp == nil { 569 panic("expected type must be set") 570 } 571 xp := g.ToPointer(x) 572 switch xp := xp.(type) { 573 case *FuncToPtr: 574 return xp.X 575 } 576 return &PtrToFunc{ 577 X: xp, 578 To: exp, 579 } 580 } 581 if xk.IsInt() { 582 if exp == nil { 583 panic("expected type must be set") 584 } 585 return &IntToFunc{ 586 X: x, 587 To: exp, 588 } 589 } 590 panic(fmt.Errorf("not a function: %T, %T", xt, x)) 591 } 592 593 func CompareFuncs(x FuncExpr, op ComparisonOp, y FuncExpr) BoolExpr { 594 if op.IsRelational() { 595 return &FuncComparison{ 596 X: x, Op: op, Y: y, 597 } 598 } 599 if !op.IsEquality() { 600 panic("must not happen") 601 } 602 // == and != simplifications 603 // always compare with the constant on the right 604 if x.IsConst() && !y.IsConst() { 605 return CompareFuncs(y, op, x) 606 } 607 return &FuncComparison{ 608 X: x, Op: op, Y: y, 609 } 610 } 611 612 var _ BoolExpr = (*FuncComparison)(nil) 613 614 type FuncComparison struct { 615 X FuncExpr 616 Op ComparisonOp 617 Y FuncExpr 618 } 619 620 func (e *FuncComparison) Visit(v Visitor) { 621 v(e.X) 622 v(e.Y) 623 } 624 625 func (e *FuncComparison) CType(types.Type) types.Type { 626 return types.BoolT() 627 } 628 629 func (e *FuncComparison) AsExpr() GoExpr { 630 x := e.X.AsExpr() 631 y := e.Y.AsExpr() 632 if _, ok := e.Y.(Nil); !ok { 633 // compare via uintptr 634 x = call(ident("libc.FuncAddr"), x) 635 y = call(ident("libc.FuncAddr"), y) 636 } 637 return &ast.BinaryExpr{ 638 X: x, 639 Op: e.Op.GoToken(), 640 Y: y, 641 } 642 } 643 644 func (e *FuncComparison) IsConst() bool { 645 return e.X.IsConst() && e.Y.IsConst() 646 } 647 648 func (e *FuncComparison) HasSideEffects() bool { 649 return e.X.HasSideEffects() || e.Y.HasSideEffects() 650 } 651 652 func (e *FuncComparison) Negate() BoolExpr { 653 return CompareFuncs(e.X, e.Op.Negate(), e.Y) 654 } 655 656 func (e *FuncComparison) Uses() []types.Usage { 657 return types.UseRead(e.X, e.Y) 658 } 659 660 type ExpandExpr struct { 661 X Expr 662 } 663 664 func (e *ExpandExpr) Visit(v Visitor) { 665 v(e.X) 666 } 667 668 func (e *ExpandExpr) CType(_ types.Type) types.Type { 669 return types.UnkT(1) 670 } 671 672 func (e *ExpandExpr) AsExpr() GoExpr { 673 panic("should be handled by CallExpr") 674 } 675 676 func (e *ExpandExpr) IsConst() bool { 677 return false 678 } 679 680 func (e *ExpandExpr) HasSideEffects() bool { 681 return false 682 } 683 684 func (e *ExpandExpr) Uses() []types.Usage { 685 return types.UseWrite(e.X) 686 }