github.com/gotranspile/cxgo@v0.3.8-0.20240118201721-29871598a6a2/convert.go (about) 1 package cxgo 2 3 import ( 4 "fmt" 5 "strings" 6 7 "modernc.org/cc/v3" 8 "modernc.org/token" 9 10 "github.com/gotranspile/cxgo/types" 11 ) 12 13 func (g *translator) newIdent(name string, t types.Type) *types.Ident { 14 if id, ok := g.env.IdentByName(name); ok { 15 if it := id.CType(nil); it.Kind().Major() == t.Kind().Major() || (it.Kind().IsBool() && t.Kind().IsInt()) { 16 return id // FIXME: this is invalid, we should consult scopes instead 17 } 18 } 19 return types.NewIdent(name, t) 20 } 21 22 func (g *translator) convMacro(name string, fnc func() Expr) Expr { 23 if g.env.ForceMacro(name) { 24 return fnc() 25 } 26 id, ok := g.macros[name] 27 if ok { 28 return IdentExpr{id} 29 } 30 x := fnc() 31 typ := x.CType(nil) 32 id = g.newIdent(name, typ) 33 g.macros[name] = id 34 return IdentExpr{id} 35 } 36 37 func (g *translator) convertIdent(scope cc.Scope, tok cc.Token, t types.Type) IdentExpr { 38 var decl []cc.Node 39 for len(scope) != 0 { 40 if nodes, ok := scope[tok.Value]; ok { 41 decl = nodes 42 break 43 } 44 scope = scope.Parent() 45 } 46 if len(decl) == 0 { 47 panic(fmt.Errorf("unresolved identifier: %s (%s)", tok, tok.Position())) 48 } 49 return g.convertIdentWith(tok.String(), t, decl...) 50 } 51 52 func (g *translator) convertIdentWith(name string, t types.Type, decls ...cc.Node) IdentExpr { 53 for _, d := range decls { 54 if id, ok := g.decls[d]; ok && id.Name == name { 55 return IdentExpr{id} 56 } 57 } 58 id := g.newIdent(name, t) 59 if to, ok := g.idents[name]; ok && to.Rename != "" { 60 id.GoName = to.Rename 61 } 62 for _, d := range decls { 63 g.decls[d] = id 64 } 65 return IdentExpr{id} 66 } 67 68 func (g *translator) replaceIdentWith(id *types.Ident, decls ...cc.Node) { 69 for _, d := range decls { 70 g.decls[d] = id 71 } 72 } 73 74 func (g *translator) tryConvertIdentOn(t types.Type, tok cc.Token) (*types.Ident, bool) { 75 loop: 76 for { 77 switch s := t.(type) { 78 case types.PtrType: 79 t = s.Elem() 80 case types.ArrayType: 81 t = s.Elem() 82 case types.Named: 83 t = s.Underlying() 84 default: 85 break loop 86 } 87 } 88 switch t := t.(type) { 89 case *types.StructType: 90 name := tok.Value.String() 91 for _, f := range t.Fields() { 92 if name == f.Name.Name { 93 return f.Name, true 94 } 95 if f.Name.Name == "" { 96 if id, ok := g.tryConvertIdentOn(f.Type(), tok); ok { 97 return id, true 98 } 99 } 100 } 101 } 102 return nil, false 103 } 104 105 func (g *translator) convertIdentOn(t types.Type, tok cc.Token) *types.Ident { 106 id, ok := g.tryConvertIdentOn(t, tok) 107 if ok { 108 return id 109 } 110 panic(fmt.Errorf("%#v.%q (%s)", t, tok.Value.String(), tok.Position())) 111 } 112 113 func (g *translator) convertFuncDef(d *cc.FunctionDefinition) []CDecl { 114 decl := d.Declarator 115 switch dd := decl.DirectDeclarator; dd.Case { 116 case cc.DirectDeclaratorFuncParam, cc.DirectDeclaratorFuncIdent: 117 sname := decl.Name().String() 118 conf := g.idents[sname] 119 ft := g.convertFuncType(conf, decl, decl.Type(), decl.Position()) 120 if !g.inCurFile(d) { 121 return nil 122 } 123 name := g.convertIdentWith(sname, ft, decl) 124 return []CDecl{ 125 &CFuncDecl{ 126 Name: name.Ident, 127 Type: ft, 128 Body: g.convertCompBlockStmt(d.CompoundStatement).In(ft), 129 Range: &Range{ 130 Start: d.Position().Offset, 131 StartLine: d.Position().Line, 132 }, 133 }, 134 } 135 default: 136 panic(dd.Case.String() + " " + dd.Position().String()) 137 } 138 } 139 140 type positioner interface { 141 Position() token.Position 142 } 143 144 func (g *translator) inCurFile(p positioner) bool { 145 name := strings.TrimLeft(p.Position().Filename, "./") 146 if g.cur == name { 147 return true 148 } else if !strings.HasSuffix(g.cur, ".c") { 149 return false 150 } 151 return g.cur[:len(g.cur)-2]+".h" == name 152 } 153 154 func (g *translator) convertInitList(typ types.Type, list *cc.InitializerList) Expr { 155 var items []*CompLitField 156 var ( 157 prev int64 = -1 // previous array init index 158 pi int64 = 0 // relative index added to the last seen item; see below 159 ) 160 for it := list; it != nil; it = it.InitializerList { 161 val := g.convertInitExpr(it.Initializer) 162 var f *CompLitField 163 if it.Designation == nil { 164 // no index in the initializer - assign automatically 165 pi++ 166 f = &CompLitField{Index: cIntLit(prev+pi, 10), Value: val} 167 items = append(items, f) 168 continue 169 } 170 f = g.convertOneDesignator(typ, it.Designation.DesignatorList, val) 171 if lit, ok := f.Index.(IntLit); ok { 172 if prev == -1 { 173 // first item - note that we started initializing indexes 174 prev = 0 175 } else if prev == lit.Int() { 176 // this was an old bug in CC where it returned stale indexes 177 // for items without any index designators 178 // it looks like it is fixed now, but we keep the workaround just in case 179 pi++ 180 f.Index = cIntLit(prev+pi, 10) 181 } else { 182 // valid index - set previous and reset relative index 183 prev = lit.Int() 184 pi = 0 185 } 186 } 187 items = append(items, f) 188 } 189 return g.NewCCompLitExpr( 190 typ, 191 items, 192 ) 193 } 194 195 func (g *translator) convertInitExpr(d *cc.Initializer) Expr { 196 switch d.Case { 197 case cc.InitializerExpr: 198 return g.convertAssignExpr(d.AssignmentExpression) 199 case cc.InitializerInitList: 200 return g.convertInitList( 201 g.convertTypeRoot(IdentConfig{}, d.Type(), d.Position()), 202 d.InitializerList, 203 ) 204 default: 205 panic(d.Case.String() + " " + d.Position().String()) 206 } 207 } 208 209 func (g *translator) convertEnum(b *cc.Declaration, typ types.Type, d *cc.EnumSpecifier) []CDecl { 210 if d.EnumeratorList == nil { 211 return nil 212 } 213 if typ == nil { 214 typ = types.UntypedIntT(g.env.IntSize()) 215 } 216 vd := &CVarDecl{ 217 Const: true, 218 Single: false, 219 CVarSpec: CVarSpec{g: g, Type: typ}, 220 } 221 var ( 222 autos = 0 // number of implicit inits 223 values = 0 // number of explicit inits 224 ) 225 for it := d.EnumeratorList; it != nil; it = it.EnumeratorList { 226 e := it.Enumerator 227 if e.Case == cc.EnumeratorExpr { 228 init := g.convertConstExpr(e.ConstantExpression) 229 vd.Inits = append(vd.Inits, init) 230 values++ 231 continue 232 } 233 vd.Inits = append(vd.Inits, nil) 234 autos++ 235 } 236 if autos == 1 && vd.Inits[0] == nil { 237 autos-- 238 values++ 239 vd.Inits[0] = cIntLit(0, 10) 240 } 241 242 // use iota if there is only one explicit init (the first one), or no explicit values are set 243 isIota := (vd.Inits[0] == nil && autos == 1) || autos == len(vd.Inits) 244 if len(vd.Inits) > 1 && vd.Inits[0] != nil && values == 1 { 245 if _, ok := cUnwrap(vd.Inits[0]).(IntLit); ok { 246 isIota = true 247 values-- 248 autos++ 249 } 250 } 251 252 if len(vd.Inits) != 0 && isIota && values != 0 { 253 panic("TODO: mixed enums") 254 } 255 var next int64 256 for it, i := d.EnumeratorList, 0; it != nil; it, i = it.EnumeratorList, i+1 { 257 e := it.Enumerator 258 if isIota { 259 if i == 0 { 260 iot := g.Iota() 261 if val := vd.Inits[0]; val != nil { 262 if l, ok := cUnwrap(val).(IntLit); !ok || !l.IsZero() { 263 iot = &CBinaryExpr{Left: iot, Op: BinOpAdd, Right: val} 264 } 265 } 266 if !typ.Kind().IsUntypedInt() { 267 iot = &CCastExpr{Type: typ, Expr: iot} 268 } 269 vd.Inits[0] = iot 270 } 271 } else { 272 if vd.Inits[i] == nil { 273 vd.Inits[i] = cIntLit(next, 10) 274 next++ 275 } else if l, ok := cUnwrap(vd.Inits[i]).(IntLit); ok { 276 next = l.Int() + 1 277 } 278 } 279 vd.Names = append(vd.Names, g.convertIdentWith(e.Token.Value.String(), typ, e).Ident) 280 } 281 if len(vd.Names) == 0 { 282 return nil 283 } 284 if isIota { 285 vd.Type = nil 286 } 287 return []CDecl{vd} 288 } 289 290 func (g *translator) convertTypedefName(d *cc.Declaration) (cc.Token, *cc.Declarator) { 291 if d.InitDeclaratorList == nil || d.InitDeclaratorList.InitDeclarator == nil { 292 panic("no decl") 293 } 294 if d.InitDeclaratorList.InitDeclaratorList != nil { 295 panic("should have one decl") 296 } 297 id := d.InitDeclaratorList.InitDeclarator 298 if id.Case != cc.InitDeclaratorDecl { 299 panic(id.Case.String()) 300 } 301 dd := id.Declarator 302 if dd.DirectDeclarator.Case != cc.DirectDeclaratorIdent { 303 panic(dd.DirectDeclarator.Case) 304 } 305 return dd.DirectDeclarator.Token, dd 306 } 307 308 func (g *translator) convertDecl(d *cc.Declaration) []CDecl { 309 inCur := g.inCurFile(d) 310 var ( 311 isConst bool 312 isVolatile bool 313 isTypedef bool 314 isStatic bool 315 isExtern bool 316 isForward bool 317 isFunc bool 318 isPrim bool 319 isAuto bool 320 typeSpec types.Type 321 enumSpec *cc.EnumSpecifier 322 names []string // used only for the hooks 323 ) 324 for il := d.InitDeclaratorList; il != nil; il = il.InitDeclaratorList { 325 id := il.InitDeclarator 326 switch id.Case { 327 case cc.InitDeclaratorDecl, cc.InitDeclaratorInit: 328 dd := id.Declarator 329 if name := dd.Name().String(); name != "" { 330 names = append(names, name) 331 } 332 } 333 } 334 spec := d.DeclarationSpecifiers 335 if spec != nil && spec.Case == cc.DeclarationSpecifiersStorage && 336 spec.StorageClassSpecifier.Case == cc.StorageClassSpecifierTypedef { 337 isTypedef = true 338 spec = spec.DeclarationSpecifiers 339 } 340 for sp := spec; sp != nil; sp = sp.DeclarationSpecifiers { 341 switch sp.Case { 342 case cc.DeclarationSpecifiersTypeQual: 343 ds := sp.TypeQualifier 344 switch ds.Case { 345 case cc.TypeQualifierConst: 346 isConst = true 347 case cc.TypeQualifierVolatile: 348 isVolatile = true 349 default: 350 panic(ds.Case.String()) 351 } 352 case cc.DeclarationSpecifiersStorage: 353 ds := sp.StorageClassSpecifier 354 switch ds.Case { 355 case cc.StorageClassSpecifierStatic: 356 isStatic = true 357 case cc.StorageClassSpecifierExtern: 358 isExtern = true 359 case cc.StorageClassSpecifierAuto: 360 isAuto = true 361 case cc.StorageClassSpecifierRegister: 362 // ignore 363 default: 364 panic(ds.Case.String()) 365 } 366 if isTypedef { 367 panic("wrong type") 368 } 369 case cc.DeclarationSpecifiersTypeSpec: 370 ds := sp.TypeSpecifier 371 switch ds.Case { 372 case cc.TypeSpecifierStructOrUnion: 373 su := ds.StructOrUnionSpecifier 374 var conf IdentConfig 375 for _, name := range names { 376 if c, ok := g.idents[name]; ok { 377 conf = c 378 break 379 } 380 } 381 switch su.Case { 382 case cc.StructOrUnionSpecifierTag: 383 // struct/union forward declaration 384 isForward = true 385 typeSpec = g.convertType(conf, su.Type(), d.Position()).(types.Named) 386 case cc.StructOrUnionSpecifierDef: 387 // struct/union declaration 388 if isForward { 389 panic("already marked as a forward decl") 390 } 391 typeSpec = g.convertType(conf, su.Type(), d.Position()) 392 default: 393 panic(su.Case.String()) 394 } 395 case cc.TypeSpecifierEnum: 396 enumSpec = ds.EnumSpecifier 397 case cc.TypeSpecifierVoid: 398 isFunc = true 399 default: 400 isPrim = true 401 } 402 case cc.DeclarationSpecifiersFunc: 403 isFunc = true 404 // TODO: use specifiers 405 default: 406 panic(sp.Case.String() + " " + sp.Position().String()) 407 } 408 } 409 _ = isStatic // FIXME: static 410 _ = isVolatile 411 _ = isAuto // FIXME: auto 412 var decls []CDecl 413 if enumSpec != nil { 414 if isForward { 415 panic("TODO") 416 } 417 if isPrim || isFunc { 418 panic("wrong type") 419 } 420 if typeSpec != nil { 421 panic("should have no type") 422 } 423 if !inCur { 424 return nil 425 } 426 var ( 427 typ types.Type 428 hasOtherDecls = false 429 ) 430 if isTypedef { 431 name, dd := g.convertTypedefName(d) 432 und := g.convertType(IdentConfig{}, dd.Type(), name.Position()) 433 nt := g.newOrFindNamedType(name.Value.String(), func() types.Type { 434 return und 435 }) 436 typ = nt 437 decls = append(decls, &CTypeDef{nt}) 438 } else if d.InitDeclaratorList != nil { 439 hasOtherDecls = true 440 } else if name := enumSpec.Token2; name.Value != 0 { 441 nt := g.newOrFindNamedType(name.Value.String(), func() types.Type { 442 return g.env.DefIntT() 443 }) 444 typ = nt 445 decls = append(decls, &CTypeDef{nt}) 446 } 447 if !hasOtherDecls { 448 decls = append(decls, g.convertEnum(d, typ, enumSpec)...) 449 } 450 } 451 if d.InitDeclaratorList == nil || d.InitDeclaratorList.InitDeclarator == nil { 452 if typeSpec == nil && enumSpec != nil { 453 return decls 454 } 455 if isTypedef && isForward { 456 panic("wrong type") 457 } 458 if isPrim || isFunc { 459 panic("wrong type") 460 } 461 if isForward { 462 if typeSpec == nil { 463 panic("no type for forward decl") 464 } 465 if !inCur || !g.conf.ForwardDecl { 466 return nil 467 } 468 } else { 469 if !inCur { 470 return nil 471 } 472 if isTypedef { 473 panic("TODO") 474 } 475 } 476 nt, ok := typeSpec.(types.Named) 477 if !ok { 478 if isForward { 479 panic("forward declaration of unnamed type") 480 } else { 481 panic(fmt.Errorf("declaration of unnamed type: %T", typeSpec)) 482 } 483 } 484 decls = append(decls, &CTypeDef{nt}) 485 return decls 486 } 487 var ( 488 added = 0 489 skipped = 0 490 ) 491 for il := d.InitDeclaratorList; il != nil; il = il.InitDeclaratorList { 492 id := il.InitDeclarator 493 switch id.Case { 494 case cc.InitDeclaratorDecl, cc.InitDeclaratorInit: 495 dd := id.Declarator 496 dname := dd.Name().String() 497 conf := g.idents[dname] 498 vt := g.convertTypeRootOpt(conf, dd.Type(), id.Position()) 499 if isTypedef && vt == nil { 500 vt = types.StructT(nil) 501 } 502 var init Expr 503 if id.Initializer != nil && inCur { 504 if isTypedef { 505 panic("init in typedef: " + id.Position().String()) 506 } 507 init = g.convertInitExpr(id.Initializer) 508 } 509 if isConst && propagateConst(vt) { 510 isConst = false 511 } 512 if isTypedef { 513 if enumSpec != nil { 514 continue 515 } 516 nt, ok := vt.(types.Named) 517 // TODO: this case is "too smart", we already handle those kind of double typedefs on a lower level 518 if !ok || nt.Name().Name != dd.Name().String() { 519 // we don't call a *From version of the method here because dd.Type() is an underlying type, 520 // not a typedef type 521 if ok && !strings.HasPrefix(nt.Name().Name, "_cxgo_") { 522 decls = append(decls, &CTypeDef{nt}) 523 } 524 if vt == nil { 525 panic("TODO: typedef of void? " + id.Position().String()) 526 } 527 nt = g.newOrFindNamedTypedef(dd.Name().String(), func() types.Type { 528 return vt 529 }) 530 if nt == nil { 531 // typedef suppressed 532 skipped++ 533 continue 534 } 535 } 536 decls = append(decls, &CTypeDef{nt}) 537 continue 538 } 539 name := g.convertIdentWith(dd.NameTok().String(), vt, dd) 540 isDecl := false 541 for di := dd.DirectDeclarator; di != nil; di = di.DirectDeclarator { 542 if di.Case == cc.DirectDeclaratorDecl { 543 isDecl = true 544 break 545 } 546 } 547 if !isDecl && !isForward { 548 if nt, ok := typeSpec.(types.Named); ok { 549 decls = append(decls, &CTypeDef{nt}) 550 } 551 } 552 if ft, ok := vt.(*types.FuncType); ok && !isDecl { 553 // forward declaration 554 if l, id, ok := g.tenv.LibIdentByName(name.Name); ok && id.CType(nil).Kind().IsFunc() { 555 // forward declaration of stdlib function 556 // we must first load the corresponding library to the real env 557 l, ok = g.env.GetLibrary(l.Name) 558 if !ok { 559 panic("cannot load stdlib") 560 } 561 id, ok = l.Idents[name.Name] 562 if !ok { 563 panic("cannot find stdlib ident") 564 } 565 g.replaceIdentWith(id, dd) 566 skipped++ 567 } else if g.conf.ForwardDecl { 568 decls = append(decls, &CFuncDecl{ 569 Name: name.Ident, 570 Type: ft, 571 Body: nil, 572 }) 573 } else { 574 skipped++ 575 } 576 } else { 577 decls = decls[:len(decls)-added] 578 if !isExtern { 579 var inits []Expr 580 if init != nil { 581 inits = []Expr{init} 582 } 583 decls = append(decls, &CVarDecl{ 584 // There is no real const in C 585 Const: false, // Const: isConst, 586 CVarSpec: CVarSpec{ 587 g: g, 588 Type: vt, 589 Names: []*types.Ident{name.Ident}, 590 Inits: inits, 591 }, 592 }) 593 } else { 594 skipped++ 595 } 596 } 597 default: 598 panic(id.Case.String()) 599 } 600 } 601 if !inCur { 602 return nil 603 } 604 if len(decls) == 0 && skipped == 0 { 605 panic("no declarations converted: " + d.Position().String()) 606 } 607 return decls 608 } 609 610 func (g *translator) convertCompStmt(d *cc.CompoundStatement) []CStmt { 611 var stmts []CStmt 612 for it := d.BlockItemList; it != nil; it = it.BlockItemList { 613 st := it.BlockItem 614 switch st.Case { 615 case cc.BlockItemDecl: 616 for _, dec := range g.convertDecl(st.Declaration) { 617 stmts = append(stmts, g.NewCDeclStmt(dec)...) 618 } 619 case cc.BlockItemStmt: 620 stmts = append(stmts, g.convertStmt(st.Statement)...) 621 default: 622 panic(st.Case.String()) 623 } 624 } 625 // TODO: shouldn't it return statements without a block? or call an optimizing version of block constructor? 626 return []CStmt{g.newBlockStmt(stmts...)} 627 } 628 629 func (g *translator) convertCompBlockStmt(d *cc.CompoundStatement) *BlockStmt { 630 stmts := g.convertCompStmt(d) 631 if len(stmts) == 1 { 632 if b, ok := stmts[0].(*BlockStmt); ok { 633 return b 634 } 635 } 636 // TODO: shouldn't it call a version that applies optimizations? 637 return g.newBlockStmt(stmts...) 638 } 639 640 func (g *translator) convertExpr(d *cc.Expression) Expr { 641 if d.Expression == nil { 642 return g.convertAssignExpr(d.AssignmentExpression) 643 } 644 var exprs []*cc.AssignmentExpression 645 for ; d != nil; d = d.Expression { 646 exprs = append(exprs, d.AssignmentExpression) 647 } 648 var m []Expr 649 for i := len(exprs) - 1; i >= 0; i-- { 650 m = append(m, g.convertAssignExpr(exprs[i])) 651 } 652 return g.NewCMultiExpr(m...) 653 } 654 655 func (g *translator) convertExprOpt(d *cc.Expression) Expr { 656 if d == nil { 657 return nil 658 } 659 return g.convertExpr(d) 660 } 661 662 func (g *translator) convertMulExpr(d *cc.MultiplicativeExpression) Expr { 663 switch d.Case { 664 case cc.MultiplicativeExpressionCast: 665 return g.convertCastExpr(d.CastExpression) 666 } 667 x := g.convertMulExpr(d.MultiplicativeExpression) 668 y := g.convertCastExpr(d.CastExpression) 669 var op BinaryOp 670 switch d.Case { 671 case cc.MultiplicativeExpressionMul: 672 op = BinOpMult 673 case cc.MultiplicativeExpressionDiv: 674 op = BinOpDiv 675 case cc.MultiplicativeExpressionMod: 676 op = BinOpMod 677 default: 678 panic(d.Case.String()) 679 } 680 return g.NewCBinaryExprT( 681 x, op, y, 682 g.convertTypeOper(d.Operand, d.Position()), 683 ) 684 } 685 686 func (g *translator) convertAddExpr(d *cc.AdditiveExpression) Expr { 687 switch d.Case { 688 case cc.AdditiveExpressionMul: 689 return g.convertMulExpr(d.MultiplicativeExpression) 690 } 691 x := g.convertAddExpr(d.AdditiveExpression) 692 y := g.convertMulExpr(d.MultiplicativeExpression) 693 var op BinaryOp 694 switch d.Case { 695 case cc.AdditiveExpressionAdd: 696 op = BinOpAdd 697 case cc.AdditiveExpressionSub: 698 op = BinOpSub 699 default: 700 panic(d.Case.String()) 701 } 702 return g.NewCBinaryExprT( 703 x, op, y, 704 g.convertTypeOper(d.Operand, d.Position()), 705 ) 706 } 707 708 func (g *translator) convertShiftExpr(d *cc.ShiftExpression) Expr { 709 switch d.Case { 710 case cc.ShiftExpressionAdd: 711 return g.convertAddExpr(d.AdditiveExpression) 712 } 713 x := g.convertShiftExpr(d.ShiftExpression) 714 y := g.convertAddExpr(d.AdditiveExpression) 715 var op BinaryOp 716 switch d.Case { 717 case cc.ShiftExpressionLsh: 718 op = BinOpLsh 719 case cc.ShiftExpressionRsh: 720 op = BinOpRsh 721 default: 722 panic(d.Case.String()) 723 } 724 return g.NewCBinaryExprT( 725 x, op, y, 726 g.convertTypeOper(d.Operand, d.Position()), 727 ) 728 } 729 730 func (g *translator) convertRelExpr(d *cc.RelationalExpression) Expr { 731 switch d.Case { 732 case cc.RelationalExpressionShift: 733 return g.convertShiftExpr(d.ShiftExpression) 734 } 735 x := g.convertRelExpr(d.RelationalExpression) 736 y := g.convertShiftExpr(d.ShiftExpression) 737 var op ComparisonOp 738 switch d.Case { 739 case cc.RelationalExpressionLt: 740 op = BinOpLt 741 case cc.RelationalExpressionGt: 742 op = BinOpGt 743 case cc.RelationalExpressionLeq: 744 op = BinOpLte 745 case cc.RelationalExpressionGeq: 746 op = BinOpGte 747 default: 748 panic(d.Case.String()) 749 } 750 return g.Compare(x, op, y) 751 } 752 753 func (g *translator) convertEqExpr(d *cc.EqualityExpression) Expr { 754 switch d.Case { 755 case cc.EqualityExpressionRel: 756 return g.convertRelExpr(d.RelationalExpression) 757 } 758 x := g.convertEqExpr(d.EqualityExpression) 759 y := g.convertRelExpr(d.RelationalExpression) 760 var op ComparisonOp 761 switch d.Case { 762 case cc.EqualityExpressionEq: 763 op = BinOpEq 764 case cc.EqualityExpressionNeq: 765 op = BinOpNeq 766 default: 767 panic(d.Case.String()) 768 } 769 return g.Compare(x, op, y) 770 } 771 772 func (g *translator) convertAndExpr(d *cc.AndExpression) Expr { 773 switch d.Case { 774 case cc.AndExpressionEq: 775 return g.convertEqExpr(d.EqualityExpression) 776 case cc.AndExpressionAnd: 777 x := g.convertAndExpr(d.AndExpression) 778 y := g.convertEqExpr(d.EqualityExpression) 779 return g.NewCBinaryExprT( 780 x, BinOpBitAnd, y, 781 g.convertTypeOper(d.Operand, d.Position()), 782 ) 783 default: 784 panic(d.Case.String()) 785 } 786 } 787 788 func (g *translator) convertLOrExcExpr(d *cc.ExclusiveOrExpression) Expr { 789 switch d.Case { 790 case cc.ExclusiveOrExpressionAnd: 791 return g.convertAndExpr(d.AndExpression) 792 case cc.ExclusiveOrExpressionXor: 793 x := g.convertLOrExcExpr(d.ExclusiveOrExpression) 794 y := g.convertAndExpr(d.AndExpression) 795 return g.NewCBinaryExprT( 796 x, BinOpBitXor, y, 797 g.convertTypeOper(d.Operand, d.Position()), 798 ) 799 default: 800 panic(d.Case.String()) 801 } 802 } 803 804 func (g *translator) convertLOrIncExpr(d *cc.InclusiveOrExpression) Expr { 805 switch d.Case { 806 case cc.InclusiveOrExpressionXor: 807 return g.convertLOrExcExpr(d.ExclusiveOrExpression) 808 case cc.InclusiveOrExpressionOr: 809 x := g.convertLOrIncExpr(d.InclusiveOrExpression) 810 y := g.convertLOrExcExpr(d.ExclusiveOrExpression) 811 return g.NewCBinaryExprT( 812 x, BinOpBitOr, y, 813 g.convertTypeOper(d.Operand, d.Position()), 814 ) 815 default: 816 panic(d.Case.String()) 817 } 818 } 819 820 func (g *translator) convertLAndExpr(d *cc.LogicalAndExpression) Expr { 821 switch d.Case { 822 case cc.LogicalAndExpressionOr: 823 return g.convertLOrIncExpr(d.InclusiveOrExpression) 824 case cc.LogicalAndExpressionLAnd: 825 x := g.convertLAndExpr(d.LogicalAndExpression) 826 y := g.convertLOrIncExpr(d.InclusiveOrExpression) 827 return And(g.ToBool(x), g.ToBool(y)) 828 default: 829 panic(d.Case.String()) 830 } 831 } 832 833 func (g *translator) convertLOrExpr(d *cc.LogicalOrExpression) Expr { 834 switch d.Case { 835 case cc.LogicalOrExpressionLAnd: 836 return g.convertLAndExpr(d.LogicalAndExpression) 837 case cc.LogicalOrExpressionLOr: 838 x := g.convertLOrExpr(d.LogicalOrExpression) 839 y := g.convertLAndExpr(d.LogicalAndExpression) 840 return Or(g.ToBool(x), g.ToBool(y)) 841 default: 842 panic(d.Case.String()) 843 } 844 } 845 846 func (g *translator) convertCondExpr(d *cc.ConditionalExpression) Expr { 847 switch d.Case { 848 case cc.ConditionalExpressionLOr: 849 return g.convertLOrExpr(d.LogicalOrExpression) 850 case cc.ConditionalExpressionCond: 851 cond := g.convertLOrExpr(d.LogicalOrExpression) 852 return g.NewCTernaryExpr( 853 g.ToBool(cond), 854 g.convertExpr(d.Expression), 855 g.convertCondExpr(d.ConditionalExpression), 856 ) 857 default: 858 panic(d.Case.String()) 859 } 860 } 861 862 func (g *translator) convertPriExpr(d *cc.PrimaryExpression) Expr { 863 switch d.Case { 864 case cc.PrimaryExpressionIdent: // x 865 if d.Token.String() == "asm" { 866 return &CAsmExpr{e: g.env.Env} 867 } 868 if d.Operand == nil { 869 panic(ErrorfWithPos(d.Position(), "empty operand for %q", d.Token.String())) 870 } 871 return g.convertIdent(d.ResolvedIn(), d.Token, g.convertTypeOper(d.Operand, d.Position())) 872 case cc.PrimaryExpressionEnum: // X 873 return g.convertIdent(d.ResolvedIn(), d.Token, g.convertTypeOper(d.Operand, d.Position())) 874 case cc.PrimaryExpressionInt: // 1 875 fnc := func() Expr { 876 v, err := parseCIntLit(d.Token.String(), g.conf.IntReformat) 877 if err != nil { 878 panic(err) 879 } 880 return v 881 } 882 if m := d.Token.Macro(); m != 0 { 883 return g.convMacro(m.String(), fnc) 884 } 885 return fnc() 886 case cc.PrimaryExpressionFloat: // 0.0 887 fnc := func() Expr { 888 v, err := parseCFloatLit(d.Token.String()) 889 if err != nil { 890 panic(err) 891 } 892 if d.Operand == nil { 893 return v 894 } 895 return g.cCast( 896 g.convertTypeOper(d.Operand, d.Position()), 897 v, 898 ) 899 } 900 if m := d.Token.Macro(); m != 0 { 901 return g.convMacro(m.String(), fnc) 902 } 903 return fnc() 904 case cc.PrimaryExpressionChar: // 'x' 905 fnc := func() Expr { 906 return cLitT( 907 d.Token.String(), CLitChar, 908 g.convertTypeOper(d.Operand, d.Position()), 909 ) 910 } 911 if m := d.Token.Macro(); m != 0 { 912 return g.convMacro(m.String(), fnc) 913 } 914 return fnc() 915 case cc.PrimaryExpressionLChar: // 'x' 916 fnc := func() Expr { 917 return cLitT( 918 d.Token.String(), CLitWChar, 919 g.convertTypeOper(d.Operand, d.Position()), 920 ) 921 } 922 if m := d.Token.Macro(); m != 0 { 923 return g.convMacro(m.String(), fnc) 924 } 925 return fnc() 926 case cc.PrimaryExpressionString: // "x" 927 fnc := func() Expr { 928 v, err := g.parseCStringLit(d.Token.String()) 929 if err != nil { 930 panic(err) 931 } 932 return v 933 } 934 if m := d.Token.Macro(); m != 0 { 935 return g.convMacro(m.String(), fnc) 936 } 937 return fnc() 938 case cc.PrimaryExpressionLString: // L"x" 939 fnc := func() Expr { 940 v, err := g.parseCWStringLit(d.Token.String()) 941 if err != nil { 942 panic(err) 943 } 944 return v 945 } 946 if m := d.Token.Macro(); m != 0 { 947 return g.convMacro(m.String(), fnc) 948 } 949 return fnc() 950 case cc.PrimaryExpressionExpr: // "(x)" 951 e := g.convertExpr(d.Expression) 952 return cParen(e) 953 case cc.PrimaryExpressionStmt: // "({...; x})" 954 stmt := g.convertCompStmt(d.CompoundStatement) 955 if len(stmt) != 1 { 956 panic("TODO") 957 } 958 stmt = stmt[0].(*BlockStmt).Stmts 959 last, ok := stmt[len(stmt)-1].(*CExprStmt) 960 if !ok { 961 // let it cause a compilation error in Go 962 return &CallExpr{ 963 Fun: g.NewFuncLit(g.env.FuncTT(g.env.DefIntT()), stmt...), 964 } 965 } 966 typ := last.Expr.CType(nil) 967 stmt = append(stmt[:len(stmt)-1], g.NewReturnStmt(last.Expr, typ)...) 968 return &CallExpr{ 969 Fun: g.NewFuncLit(g.env.FuncTT(typ), stmt...), 970 } 971 default: 972 panic(fmt.Errorf("%v (%v)", d.Case, d.Position())) 973 } 974 } 975 976 func (g *translator) convertOneDesignator(typ types.Type, list *cc.DesignatorList, val Expr) *CompLitField { 977 d := list.Designator 978 var ( 979 f *CompLitField 980 sub types.Type 981 ) 982 switch d.Case { 983 case cc.DesignatorIndex: 984 f = &CompLitField{Index: g.convertConstExpr(d.ConstantExpression)} 985 sub = typ.(types.ArrayType).Elem() 986 case cc.DesignatorField: 987 f = &CompLitField{Field: g.convertIdentOn(typ, d.Token2)} 988 sub = f.Field.CType(nil) 989 case cc.DesignatorField2: 990 f = &CompLitField{Field: g.convertIdentOn(typ, d.Token)} 991 sub = f.Field.CType(nil) 992 default: 993 panic(d.Case.String() + " " + d.Position().String()) 994 } 995 if list.DesignatorList == nil { 996 f.Value = val 997 return f 998 } 999 f2 := g.convertOneDesignator(sub, list.DesignatorList, val) 1000 f.Value = g.NewCCompLitExpr(sub, []*CompLitField{f2}) 1001 return f 1002 } 1003 1004 func (g *translator) convertPostfixExpr(d *cc.PostfixExpression) Expr { 1005 switch d.Case { 1006 case cc.PostfixExpressionPrimary: 1007 return g.convertPriExpr(d.PrimaryExpression) 1008 case cc.PostfixExpressionIndex: // "x[y]" 1009 return g.NewCIndexExpr( 1010 g.convertPostfixExpr(d.PostfixExpression), 1011 g.convertExpr(d.Expression), 1012 g.convertTypeOper(d.Operand, d.Position()), 1013 ) 1014 case cc.PostfixExpressionCall: // x([args]) 1015 fnc := g.convertPostfixExpr(d.PostfixExpression) 1016 var args []Expr 1017 for it := d.ArgumentExpressionList; it != nil; it = it.ArgumentExpressionList { 1018 args = append(args, g.convertAssignExpr(it.AssignmentExpression)) 1019 } 1020 return g.NewCCallExpr(g.ToFunc(fnc, ToFuncExpr(fnc.CType(nil))), args) 1021 case cc.PostfixExpressionPSelect: // x->y 1022 exp := g.convertPostfixExpr(d.PostfixExpression) 1023 if _, ok := exp.CType(nil).(types.ArrayType); ok { // pointer accesses might be an array 1024 return NewCSelectExpr( 1025 g.NewCIndexExpr( 1026 exp, 1027 cUintLit(0, 10), // index the first element 1028 g.convertTypeOper(d.Operand, d.Position()), 1029 ), g.convertIdentOn(exp.CType(nil), d.Token2), 1030 ) 1031 } 1032 return NewCSelectExpr( 1033 exp, g.convertIdentOn(exp.CType(nil), d.Token2), 1034 ) 1035 case cc.PostfixExpressionSelect: // x.y 1036 exp := g.convertPostfixExpr(d.PostfixExpression) 1037 return NewCSelectExpr( 1038 exp, g.convertIdentOn(exp.CType(nil), d.Token2), 1039 ) 1040 case cc.PostfixExpressionInc: // x++ 1041 x := g.convertPostfixExpr(d.PostfixExpression) 1042 return g.NewCPostfixExpr(x, false) 1043 case cc.PostfixExpressionDec: // x-- 1044 x := g.convertPostfixExpr(d.PostfixExpression) 1045 return g.NewCPostfixExpr(x, true) 1046 case cc.PostfixExpressionComplit: 1047 return g.convertInitList( 1048 g.convertType(IdentConfig{}, d.TypeName.Type(), d.Position()), 1049 d.InitializerList, 1050 ) 1051 default: 1052 panic(d.Case.String() + " " + d.Position().String()) 1053 } 1054 } 1055 1056 func (g *translator) convertCastExpr(d *cc.CastExpression) Expr { 1057 switch d.Case { 1058 case cc.CastExpressionUnary: 1059 return g.convertUnaryExpr(d.UnaryExpression) 1060 case cc.CastExpressionCast: 1061 x := g.convertCastExpr(d.CastExpression) 1062 if k := d.Operand.Type().Kind(); k == cc.Invalid || k == cc.Void { 1063 return x 1064 } 1065 return g.cCast( 1066 g.convertTypeOper(d.Operand, d.Position()), 1067 x, 1068 ) 1069 default: 1070 panic(d.Case.String()) 1071 } 1072 } 1073 1074 func (g *translator) convertUnaryExpr(d *cc.UnaryExpression) Expr { 1075 switch d.Case { 1076 case cc.UnaryExpressionPostfix: 1077 return g.convertPostfixExpr(d.PostfixExpression) 1078 case cc.UnaryExpressionInc: // ++x 1079 x := g.convertUnaryExpr(d.UnaryExpression) 1080 return g.NewCPrefixExpr(x, false) 1081 case cc.UnaryExpressionDec: // --x 1082 x := g.convertUnaryExpr(d.UnaryExpression) 1083 return g.NewCPrefixExpr(x, true) 1084 case cc.UnaryExpressionSizeofExpr: // sizeof x 1085 return g.NewCUnaryExprT( 1086 UnarySizeof, 1087 g.convertUnaryExpr(d.UnaryExpression), 1088 g.convertTypeOper(d.Operand, d.Position()), 1089 ) 1090 case cc.UnaryExpressionSizeofType: // sizeof tp 1091 return g.SizeofT( 1092 g.convertType(IdentConfig{}, d.TypeName.Type(), d.Position()), 1093 nil, 1094 ) 1095 case cc.UnaryExpressionAlignofType: // alignof tp 1096 return g.AlignofT( 1097 g.convertType(IdentConfig{}, d.TypeName.Type(), d.Position()), 1098 nil, 1099 ) 1100 } 1101 var op UnaryOp 1102 switch d.Case { 1103 case cc.UnaryExpressionAddrof: // &x 1104 x := g.convertCastExpr(d.CastExpression) 1105 return g.cAddr(x) 1106 case cc.UnaryExpressionDeref: // *x 1107 x := g.convertCastExpr(d.CastExpression) 1108 typ := g.convertTypeOper(d.Operand, d.Position()) 1109 return g.cDerefT(x, typ) 1110 case cc.UnaryExpressionPlus: // +x 1111 op = UnaryPlus 1112 case cc.UnaryExpressionMinus: // -x 1113 op = UnaryMinus 1114 case cc.UnaryExpressionCpl: // ~x 1115 op = UnaryXor 1116 case cc.UnaryExpressionNot: // !x 1117 x := g.convertCastExpr(d.CastExpression) 1118 return g.cNot(x) 1119 default: 1120 panic(d.Case.String()) 1121 } 1122 x := g.convertCastExpr(d.CastExpression) 1123 if d.Operand == nil { 1124 return g.NewCUnaryExpr( 1125 op, x, 1126 ) 1127 } 1128 return g.NewCUnaryExprT( 1129 op, x, 1130 g.convertTypeOper(d.Operand, d.Position()), 1131 ) 1132 } 1133 1134 func (g *translator) convertConstExpr(d *cc.ConstantExpression) Expr { 1135 return g.convertCondExpr(d.ConditionalExpression) 1136 } 1137 1138 func (g *translator) convertAssignExpr(d *cc.AssignmentExpression) Expr { 1139 switch d.Case { 1140 case cc.AssignmentExpressionCond: 1141 return g.convertCondExpr(d.ConditionalExpression) 1142 } 1143 x := g.convertUnaryExpr(d.UnaryExpression) 1144 y := g.convertAssignExpr(d.AssignmentExpression) 1145 var op BinaryOp 1146 switch d.Case { 1147 case cc.AssignmentExpressionAssign: 1148 op = "" 1149 case cc.AssignmentExpressionMul: 1150 op = BinOpMult 1151 case cc.AssignmentExpressionDiv: 1152 op = BinOpDiv 1153 case cc.AssignmentExpressionMod: 1154 op = BinOpMod 1155 case cc.AssignmentExpressionAdd: 1156 op = BinOpAdd 1157 case cc.AssignmentExpressionSub: 1158 op = BinOpSub 1159 case cc.AssignmentExpressionLsh: 1160 op = BinOpLsh 1161 case cc.AssignmentExpressionRsh: 1162 op = BinOpRsh 1163 case cc.AssignmentExpressionAnd: 1164 op = BinOpBitAnd 1165 case cc.AssignmentExpressionXor: 1166 op = BinOpBitXor 1167 case cc.AssignmentExpressionOr: 1168 op = BinOpBitOr 1169 default: 1170 panic(d.Case.String()) 1171 } 1172 return g.NewCAssignExpr( 1173 x, op, y, 1174 ) 1175 } 1176 1177 func (g *translator) convertLabelStmt(st *cc.LabeledStatement) []CStmt { 1178 switch st.Case { 1179 case cc.LabeledStatementLabel: // label: 1180 stmts := g.convertStmt(st.Statement) 1181 return append([]CStmt{ 1182 &CLabelStmt{Label: st.Token.Value.String()}, 1183 }, stmts...) 1184 case cc.LabeledStatementCaseLabel: // case xxx: 1185 return []CStmt{ 1186 g.NewCaseStmt( 1187 g.convertConstExpr(st.ConstantExpression), 1188 g.convertStmt(st.Statement)..., 1189 ), 1190 } 1191 case cc.LabeledStatementDefault: // default: 1192 return []CStmt{ 1193 g.NewCaseStmt( 1194 nil, 1195 g.convertStmt(st.Statement)..., 1196 ), 1197 } 1198 default: 1199 panic(st.Case.String()) 1200 } 1201 } 1202 1203 func (g *translator) convertExprStmt(st *cc.ExpressionStatement) []CStmt { 1204 var exprs []*cc.AssignmentExpression 1205 for e := st.Expression; e != nil; e = e.Expression { 1206 exprs = append(exprs, e.AssignmentExpression) 1207 } 1208 var stmts []CStmt 1209 for i := len(exprs) - 1; i >= 0; i-- { 1210 stmts = append(stmts, NewCExprStmt(g.convertAssignExpr(exprs[i]))...) 1211 } 1212 return stmts 1213 } 1214 1215 func (g *translator) convertSelStmt(st *cc.SelectionStatement) []CStmt { 1216 switch st.Case { 1217 case cc.SelectionStatementIf: // if (x) 1218 cond := g.convertExpr(st.Expression) 1219 return []CStmt{ 1220 g.NewCIfStmt( 1221 g.ToBool(cond), 1222 []CStmt{g.convertBlockStmt(st.Statement)}, 1223 nil, 1224 ), 1225 } 1226 case cc.SelectionStatementIfElse: // if (x) else 1227 cond := g.convertExpr(st.Expression) 1228 return []CStmt{ 1229 g.NewCIfStmt( 1230 g.ToBool(cond), 1231 []CStmt{g.convertBlockStmt(st.Statement)}, 1232 g.toElseStmt(g.convertOneStmt(st.Statement2)), 1233 ), 1234 } 1235 case cc.SelectionStatementSwitch: // switch (x) 1236 return []CStmt{g.NewCSwitchStmt( 1237 g.convertExpr(st.Expression), 1238 []CStmt{g.convertBlockStmt(st.Statement)}, 1239 )} 1240 default: 1241 panic(st.Case.String()) 1242 } 1243 } 1244 1245 func (g *translator) convertIterStmt(st *cc.IterationStatement) []CStmt { 1246 switch st.Case { 1247 case cc.IterationStatementWhile: 1248 x := g.convertExprOpt(st.Expression) 1249 var cond BoolExpr 1250 if x != nil { 1251 cond = g.ToBool(x) 1252 } 1253 return []CStmt{ 1254 g.NewCForStmt( 1255 nil, 1256 cond, 1257 nil, 1258 []CStmt{g.convertBlockStmt(st.Statement)}, 1259 ), 1260 } 1261 case cc.IterationStatementDo: 1262 return []CStmt{ 1263 g.NewCDoWhileStmt( 1264 g.convertExprOpt(st.Expression), 1265 []CStmt{g.convertBlockStmt(st.Statement)}, 1266 ), 1267 } 1268 case cc.IterationStatementFor: 1269 x := g.convertExprOpt(st.Expression2) 1270 var cond BoolExpr 1271 if x != nil { 1272 cond = g.ToBool(x) 1273 } 1274 return []CStmt{ 1275 g.NewCForStmt( 1276 g.convertExprOpt(st.Expression), 1277 cond, 1278 g.convertExprOpt(st.Expression3), 1279 []CStmt{g.convertBlockStmt(st.Statement)}, 1280 ), 1281 } 1282 case cc.IterationStatementForDecl: 1283 var cur *CVarDecl 1284 for _, d := range g.convertDecl(st.Declaration) { 1285 d := d.(*CVarDecl) 1286 if cur == nil { 1287 cur = d 1288 continue 1289 } 1290 if !types.Same(cur.Type, d.Type) { 1291 panic(fmt.Errorf("different types in a declaration: %v vs %v (%s)", cur.Type, d.Type, st.Position())) 1292 } 1293 cur.Single = true 1294 n1, n2 := len(cur.Names), len(d.Names) 1295 cur.Names = append(cur.Names, d.Names...) 1296 if len(cur.Inits) == 0 && len(d.Inits) == 0 { 1297 continue 1298 } 1299 if len(cur.Inits) == 0 { 1300 cur.Inits = make([]Expr, n1, n1+n2) 1301 } 1302 if len(d.Inits) == 0 { 1303 cur.Inits = append(cur.Inits, make([]Expr, n2)...) 1304 } else { 1305 cur.Inits = append(cur.Inits, d.Inits...) 1306 } 1307 } 1308 x := g.convertExprOpt(st.Expression) 1309 var cond BoolExpr 1310 if x != nil { 1311 cond = g.ToBool(x) 1312 } 1313 return []CStmt{ 1314 g.NewCForDeclStmt( 1315 cur, 1316 cond, 1317 g.convertExprOpt(st.Expression2), 1318 []CStmt{g.convertBlockStmt(st.Statement)}, 1319 ), 1320 } 1321 default: 1322 panic(st.Case.String() + " " + st.Position().String()) 1323 } 1324 } 1325 1326 func (g *translator) convertJumpStmt(st *cc.JumpStatement) []CStmt { 1327 switch st.Case { 1328 case cc.JumpStatementGoto: // goto x 1329 return []CStmt{ 1330 &CGotoStmt{Label: st.Token2.Value.String()}, 1331 } 1332 case cc.JumpStatementContinue: // continue 1333 return []CStmt{ 1334 &CContinueStmt{}, 1335 } 1336 case cc.JumpStatementBreak: // break 1337 return []CStmt{ 1338 &CBreakStmt{}, 1339 } 1340 case cc.JumpStatementReturn: // return 1341 return g.NewReturnStmt( 1342 g.convertExprOpt(st.Expression), 1343 nil, 1344 ) 1345 default: 1346 panic(st.Case.String()) 1347 } 1348 } 1349 1350 func (g *translator) convertAsmStmt(d *cc.AsmStatement) []CStmt { 1351 // TODO 1352 return NewCExprStmt(&CAsmExpr{e: g.env.Env, typ: types.UnkT(1)}) 1353 } 1354 1355 func (g *translator) convertStmt(d *cc.Statement) []CStmt { 1356 switch d.Case { 1357 case cc.StatementLabeled: 1358 return g.convertLabelStmt(d.LabeledStatement) 1359 case cc.StatementCompound: 1360 return g.convertCompStmt(d.CompoundStatement) 1361 case cc.StatementExpr: 1362 return g.convertExprStmt(d.ExpressionStatement) 1363 case cc.StatementSelection: 1364 return g.convertSelStmt(d.SelectionStatement) 1365 case cc.StatementIteration: 1366 return g.convertIterStmt(d.IterationStatement) 1367 case cc.StatementJump: 1368 return g.convertJumpStmt(d.JumpStatement) 1369 case cc.StatementAsm: 1370 return g.convertAsmStmt(d.AsmStatement) 1371 default: 1372 panic(d.Case.String()) 1373 } 1374 } 1375 1376 func (g *translator) convertOneStmt(d *cc.Statement) CStmt { 1377 stmts := g.convertStmt(d) 1378 if len(stmts) == 1 { 1379 return stmts[0] 1380 } 1381 return g.NewCBlock(stmts...) 1382 } 1383 1384 func (g *translator) convertBlockStmt(d *cc.Statement) *BlockStmt { 1385 stmts := g.convertStmt(d) 1386 if len(stmts) == 1 { 1387 if b, ok := stmts[0].(*BlockStmt); ok { 1388 return b 1389 } 1390 } 1391 return g.NewCBlock(stmts...) 1392 }