github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/transpiler/call.go (about) 1 // This file contains functions for transpiling function calls (invocations). 2 3 package transpiler 4 5 import ( 6 "bytes" 7 "fmt" 8 goast "go/ast" 9 "go/printer" 10 "go/token" 11 "strconv" 12 "strings" 13 14 "github.com/Konstantin8105/c4go/ast" 15 "github.com/Konstantin8105/c4go/program" 16 "github.com/Konstantin8105/c4go/types" 17 "github.com/Konstantin8105/c4go/util" 18 ) 19 20 func getMemberName(firstChild ast.Node) (name string, ok bool) { 21 switch fc := firstChild.(type) { 22 case *ast.MemberExpr: 23 return fc.Name, true 24 25 case *ast.ParenExpr: 26 return getMemberName(fc.Children()[0]) 27 28 case *ast.ImplicitCastExpr: 29 return getMemberName(fc.Children()[0]) 30 31 case *ast.CStyleCastExpr: 32 return getMemberName(fc.Children()[0]) 33 34 } 35 return "", false 36 } 37 38 const undefineFunctionName string = "C4GO_UNDEFINE_NAME" 39 40 func getName(p *program.Program, firstChild ast.Node) (name string, err error) { 41 switch fc := firstChild.(type) { 42 case *ast.DeclRefExpr: 43 return fc.Name, nil 44 45 case *ast.GenericSelectionExpr: 46 if len(fc.Children()) == 0 { 47 return undefineFunctionName, nil 48 } 49 return getName(p, fc.Children()[0]) 50 51 case *ast.MemberExpr: 52 var expr goast.Expr 53 expr, _, _, _, err = transpileToExpr(fc, p, false) 54 if err != nil { 55 return 56 } 57 var buf bytes.Buffer 58 err = printer.Fprint(&buf, token.NewFileSet(), expr) 59 if err != nil { 60 return 61 } 62 return buf.String(), nil 63 64 case *ast.CallExpr: 65 if len(fc.Children()) == 0 { 66 return undefineFunctionName, nil 67 } 68 return getName(p, fc.Children()[0]) 69 70 case *ast.ParenExpr: 71 if len(fc.Children()) == 0 { 72 return undefineFunctionName, nil 73 } 74 return getName(p, fc.Children()[0]) 75 76 case *ast.UnaryOperator: 77 if len(fc.Children()) == 0 { 78 return undefineFunctionName, nil 79 } 80 return getName(p, fc.Children()[0]) 81 82 case *ast.ImplicitCastExpr: 83 if len(fc.Children()) == 0 { 84 return undefineFunctionName, nil 85 } 86 return getName(p, fc.Children()[0]) 87 88 case *ast.CStyleCastExpr: 89 if len(fc.Children()) == 0 { 90 return undefineFunctionName, nil 91 } 92 if fc.Kind == ast.CStyleCastExprNullToPointer { 93 // CallExpr 'void' 94 // `-ParenExpr 'void (*)(void)' 95 // `-CStyleCastExpr 'void (*)(void)' <NullToPointer> 96 // `-IntegerLiteral 'int' 0 97 return "nil", fmt.Errorf("no name for NullToPointer") 98 } 99 return getName(p, fc.Children()[0]) 100 101 case *ast.ArraySubscriptExpr: 102 var expr goast.Expr 103 expr, _, _, _, err = transpileArraySubscriptExpr(fc, p) 104 if err != nil { 105 return 106 } 107 var buf bytes.Buffer 108 err = printer.Fprint(&buf, token.NewFileSet(), expr) 109 if err != nil { 110 return 111 } 112 return buf.String(), nil 113 } 114 115 return "", fmt.Errorf("cannot getName for: %#v", firstChild) 116 } 117 118 // simplificationCallExprPrintf - minimize Go code 119 // transpile C code : printf("Hello") 120 // to Go code : fmt_Printf("Hello") 121 // AST example : 122 // CallExpr <> 'int' 123 // |-ImplicitCastExpr <> 'int (*)(const char *, ...)' <FunctionToPointerDecay> 124 // | `-DeclRefExpr <> 'int (const char *, ...)' Function 0x2fec178 'printf' 'int (const char *, ...)' 125 // `-ImplicitCastExpr <> 'const char *' <BitCast> 126 // 127 // `-ImplicitCastExpr <> 'char *' <ArrayToPointerDecay> 128 // `-StringLiteral <> 'char [6]' lvalue "Hello" 129 func simplificationCallExprPrintf(call *ast.CallExpr, p *program.Program) ( 130 expr *goast.CallExpr, ok bool) { 131 132 var isPrintfCode bool 133 var printfText string 134 if call.Type == "int" && len(call.ChildNodes) == 2 { 135 var step1 bool 136 if impl, ok := call.ChildNodes[0].(*ast.ImplicitCastExpr); ok && len(impl.ChildNodes) == 1 { 137 if decl, ok := impl.ChildNodes[0].(*ast.DeclRefExpr); ok && decl.Name == "printf" { 138 if impl.Type == "int (*)(const char *, ...)" { 139 step1 = true 140 } 141 } 142 } 143 var step2 bool 144 if impl, ok := call.ChildNodes[1].(*ast.ImplicitCastExpr); ok { 145 if impl.Type == "const char *" && len(impl.ChildNodes) == 1 { 146 if impl2, ok := impl.ChildNodes[0].(*ast.ImplicitCastExpr); ok { 147 if impl2.Type == "char *" && len(impl2.ChildNodes) == 1 { 148 if str, ok := impl2.ChildNodes[0].(*ast.StringLiteral); ok { 149 step2 = true 150 printfText = str.Value 151 } 152 } 153 } 154 } 155 } 156 if step1 && step2 { 157 isPrintfCode = true 158 } 159 } 160 161 if !isPrintfCode { 162 return 163 } 164 165 // 0: *ast.ExprStmt { 166 // . X: *ast.CallExpr { 167 // . . Fun: *ast.SelectorExpr { 168 // . . . X: *ast.Ident { 169 // . . . . NamePos: 8:2 170 // . . . . Name: "fmt" 171 // . . . } 172 // . . . Sel: *ast.Ident { 173 // . . . . NamePos: 8:6 174 // . . . . Name: "Printf" 175 // . . . } 176 // . . } 177 // . . Lparen: 8:12 178 // . . Args: []ast.Expr (len = 1) { 179 // . . . 0: *ast.BasicLit { 180 // . . . . ValuePos: 8:13 181 // . . . . Kind: STRING 182 // . . . . Value: "\"Hello, Golang\\n\"" 183 // . . . } 184 // . . } 185 // . . Ellipsis: - 186 // . . Rparen: 8:30 187 // . } 188 // } 189 p.AddImport("fmt") 190 printfText = strconv.Quote(printfText) 191 return util.NewCallExpr("fmt"+"."+"Printf", 192 &goast.BasicLit{ 193 Kind: token.STRING, 194 Value: printfText, 195 }), true 196 } 197 198 // transpileCallExpr transpiles expressions that calls a function, for example: 199 // 200 // foo("bar") 201 // 202 // It returns three arguments; the Go AST expression, the C type (that is 203 // returned by the function) and any error. If there is an error returned you 204 // can assume the first two arguments will not contain any useful information. 205 func transpileCallExpr(n *ast.CallExpr, p *program.Program) ( 206 expr *goast.CallExpr, resultType string, 207 preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { 208 defer func() { 209 if err != nil { 210 err = fmt.Errorf("error in transpileCallExpr : %v", err) 211 } 212 if resultType == "" { 213 resultType = n.Type 214 } 215 }() 216 217 functionName, err := getName(p, n) 218 if err != nil { 219 p.AddMessage(p.GenerateWarningMessage(err, n)) 220 err = nil 221 functionName = undefineFunctionName 222 } 223 functionName = util.ConvertFunctionNameFromCtoGo(functionName) 224 225 defer func() { 226 if err != nil { 227 err = fmt.Errorf("name of call function is %v. %v", 228 functionName, err) 229 } 230 }() 231 232 // specific for va_list 233 changeVaListFuncs(&functionName) 234 235 // function "malloc" from stdlib.h 236 // 237 // Change from "malloc" to "calloc" 238 // 239 // CallExpr <> 'void *' 240 // |-ImplicitCastExpr <> 'void *(*)(unsigned long)' <FunctionToPointerDecay> 241 // | `-DeclRefExpr <> 'void *(unsigned long)' Function 'malloc' 'void *(unsigned long)' 242 // `-ImplicitCastExpr <> 'unsigned long' <IntegralCast> 243 // `- ... 244 // 245 // CallExpr <> 'void *' 246 // |-ImplicitCastExpr <> 'void *(*)(unsigned long, unsigned long)' <FunctionToPointerDecay> 247 // | `-DeclRefExpr <> 'void *(unsigned long, unsigned long)' Function 'calloc' 'void *(unsigned long, unsigned long)' 248 // |-ImplicitCastExpr <> 'unsigned long' <IntegralCast> 249 // | `- ... 250 // `-UnaryExprOrTypeTraitExpr <> 'unsigned long' sizeof 'char' 251 if p.IncludeHeaderIsExists("stdlib.h") { 252 if functionName == "malloc" && len(n.Children()) == 2 { 253 // Change from "malloc" to "calloc" 254 unary, expression, back, err := findAndReplaceUnaryExprOrTypeTraitExpr(&n.Children()[1]) 255 if err != nil { 256 back() 257 return transpileCallExprCalloc(n.Children()[1], 258 &ast.UnaryExprOrTypeTraitExpr{ 259 Function: "sizeof", 260 Type1: "unsigned long", 261 Type2: "char", 262 }, p) 263 } 264 return transpileCallExprCalloc(expression, unary.(*ast.UnaryExprOrTypeTraitExpr), p) 265 } 266 } 267 268 if p.IncludeHeaderIsExists("stdio.h") && 269 (functionName == "setbuf" || functionName == "setvbuf") { 270 // ignore function 271 return 272 } 273 274 // function "calloc" from stdlib.h 275 if p.IncludeHeaderIsExists("stdlib.h") { 276 if functionName == "calloc" && len(n.Children()) == 3 { 277 if unary, ok := n.Children()[2].(*ast.UnaryExprOrTypeTraitExpr); ok { 278 return transpileCallExprCalloc(n.Children()[1], unary, p) 279 } 280 281 call := &ast.CallExpr{} 282 283 call.AddChild(&ast.ImplicitCastExpr{ 284 Type: "void *(*)(unsigned long)", 285 }) 286 call.ChildNodes[0].(*ast.ImplicitCastExpr).AddChild(&ast.DeclRefExpr{ 287 Type: "void *(unsigned long)", 288 Name: "malloc", 289 }) 290 291 bin := &ast.BinaryOperator{ 292 Operator: "*", 293 Type: "unsigned long", 294 } 295 bin.AddChild(n.ChildNodes[1]) 296 bin.AddChild(n.ChildNodes[2]) 297 call.AddChild(bin) 298 299 return transpileCallExpr(call, p) 300 } 301 } 302 303 // function "qsort" from stdlib.h 304 if p.IncludeHeaderIsExists("stdlib.h") { 305 if functionName == "qsort" && len(n.Children()) == 5 { 306 return transpileCallExprQsort(n, p) 307 } 308 } 309 310 // function "bsearch" from stdlib.h 311 if p.IncludeHeaderIsExists("stdlib.h") { 312 if functionName == "bsearch" && len(n.Children()) == 6 { 313 return transpileCallExprBsearch(n, p) 314 } 315 } 316 317 // function "printf" from stdio.h simplification 318 if p.IncludeHeaderIsExists("stdio.h") { 319 if functionName == "printf" && len(n.Children()) == 2 { 320 if e, ok := simplificationCallExprPrintf(n, p); ok { 321 return e, "int", nil, nil, nil 322 } 323 } 324 } 325 326 // Get the function definition from it's name. The case where it is not 327 // defined is handled below (we haven't seen the prototype yet). 328 functionDef := p.GetFunctionDefinition(functionName) 329 330 if functionDef != nil { 331 p.SetCalled(functionName) 332 } 333 334 if functionDef == nil { 335 // We do not have a prototype for the function, but we should not exit 336 // here. Instead we will create a mock definition for it so that this 337 // transpile function will always return something and continue. 338 // 339 // The mock function definition is never actually saved to the program 340 // definitions, so each time we see the CallExpr it will run this every 341 // time. This is so if we come across the real prototype later it will 342 // be handled correctly. Or at least "more" correctly. 343 functionDef = &program.DefinitionFunction{ 344 Name: functionName, 345 } 346 if len(n.Children()) > 0 { 347 348 checker := func(t string) bool { 349 return util.IsFunction(t) || types.IsTypedefFunction(p, t) 350 } 351 352 var finder func(n ast.Node) string 353 finder = func(n ast.Node) (t string) { 354 switch v := n.(type) { 355 case *ast.ImplicitCastExpr: 356 t = v.Type 357 case *ast.ParenExpr: 358 t = v.Type 359 case *ast.CStyleCastExpr: 360 t = v.Type 361 default: 362 panic(fmt.Errorf("add type %T", n)) 363 } 364 if checker(t) { 365 return t 366 } 367 if len(n.Children()) == 0 { 368 return "" 369 } 370 return finder(n.Children()[0]) 371 } 372 373 if t := finder(n.Children()[0]); checker(t) { 374 if v, ok := p.TypedefType[t]; ok { 375 t = v 376 } else { 377 if types.IsTypedefFunction(p, t) { 378 t = t[0 : len(t)-len(" *")] 379 t = p.TypedefType[t] 380 } 381 } 382 prefix, _, fields, returns, err := util.ParseFunction(t) 383 if err != nil { 384 p.AddMessage(p.GenerateWarningMessage(fmt.Errorf( 385 "cannot resolve function : %v", err), n)) 386 return nil, "", nil, nil, err 387 } 388 if len(prefix) != 0 { 389 p.AddMessage(p.GenerateWarningMessage(fmt.Errorf( 390 "prefix `%v` is not used in type : %v", 391 prefix, t), n)) 392 } 393 functionDef.ReturnType = returns[0] 394 functionDef.ArgumentTypes = fields 395 } 396 } 397 } else { 398 399 // type correction for definition function in 400 // package program 401 var ok bool 402 for pos, arg := range n.Children() { 403 if pos == 0 { 404 continue 405 } 406 if pos >= len(functionDef.ArgumentTypes) { 407 continue 408 } 409 if arg, ok = arg.(*ast.ImplicitCastExpr); ok { 410 arg.(*ast.ImplicitCastExpr).Type = functionDef.ArgumentTypes[pos-1] 411 } 412 } 413 } 414 415 if functionDef.Substitution != "" { 416 parts := strings.Split(functionDef.Substitution, ".") 417 importName := strings.Join(parts[:len(parts)-1], ".") 418 p.AddImport(importName) 419 420 parts2 := strings.Split(functionDef.Substitution, "/") 421 functionName = parts2[len(parts2)-1] 422 } 423 424 args := []goast.Expr{} 425 argTypes := []string{} 426 i := 0 427 for _, arg := range n.Children()[1:] { 428 if bin, ok := arg.(*ast.BinaryOperator); ok && bin.Operator == "=" { 429 // example : 430 // from : 431 // call(val = 43); 432 // to: 433 // call(val = 43,val); 434 var b ast.BinaryOperator 435 b.Type = bin.Type 436 b.Operator = "," 437 b.AddChild(arg) 438 b.AddChild(bin.Children()[0]) 439 arg = &b 440 } 441 if cmp, ok := arg.(*ast.CompoundAssignOperator); ok { 442 // example : 443 // from : 444 // call(val += 43); 445 // to: 446 // call(val += 43,val); 447 var b ast.BinaryOperator 448 b.Type = cmp.Type 449 b.Operator = "," 450 b.AddChild(arg) 451 b.AddChild(cmp.Children()[0]) 452 arg = &b 453 } 454 e, eType, newPre, newPost, err := atomicOperation(arg, p) 455 if err != nil { 456 err = fmt.Errorf("argument position is %d. %v", i, err) 457 p.AddMessage(p.GenerateWarningMessage(err, arg)) 458 return nil, "unknown2", nil, nil, err 459 } 460 argTypes = append(argTypes, eType) 461 preStmts, postStmts = combinePreAndPostStmts( 462 preStmts, postStmts, newPre, newPost) 463 464 args = append(args, e) 465 i++ 466 } 467 468 // These are the arguments once any transformations have taken place. 469 realArgs := []goast.Expr{} 470 471 // Apply transformation if needed. A transformation rearranges the return 472 // value(s) and parameters. It is also used to indicate when a variable must 473 // be passed by reference. 474 if functionDef.ReturnParameters != nil || functionDef.Parameters != nil { 475 for i, a := range functionDef.Parameters { 476 byReference := false 477 478 // Negative position means that it must be passed by reference. 479 if a < 0 { 480 byReference = true 481 a = -a 482 } 483 484 // Rearrange the arguments. The -1 is because 0 would be the return 485 // value. 486 realArg := args[a-1] 487 488 if byReference { 489 // We have to create a temporary variable to pass by reference. 490 // Then we can assign the real variable from it. 491 realArg = &goast.UnaryExpr{ 492 Op: token.AND, 493 X: args[i], 494 } 495 } else { 496 realArg, err = types.CastExpr(p, realArg, argTypes[i], 497 functionDef.ArgumentTypes[i]) 498 p.AddMessage(p.GenerateWarningMessage(err, n)) 499 500 if realArg == nil { 501 realArg = util.NewNil() 502 } 503 } 504 505 if realArg == nil { 506 return nil, "", preStmts, postStmts, 507 fmt.Errorf("real argument is nil in function : %s", functionName) 508 } 509 510 realArgs = append(realArgs, realArg) 511 } 512 } else { 513 // Keep all the arguments the same. But make sure we cast to the correct 514 // types. 515 // Example of functionDef.ArgumentTypes : 516 // [void *, int] 517 // [char *, char * , ...] 518 // Example of args: 519 // [void *, int] 520 // [char *, char *, char *, int, double] 521 // 522 for i, a := range args { 523 realType := "unknownType" 524 if i < len(functionDef.ArgumentTypes) { 525 if len(functionDef.ArgumentTypes) > 1 && 526 i >= len(functionDef.ArgumentTypes)-1 && 527 functionDef.ArgumentTypes[len(functionDef.ArgumentTypes)-1] == "..." { 528 realType = functionDef.ArgumentTypes[len(functionDef.ArgumentTypes)-2] 529 } else { 530 if len(functionDef.ArgumentTypes) > 0 { 531 if len(functionDef.ArgumentTypes[i]) != 0 { 532 realType = functionDef.ArgumentTypes[i] 533 if strings.TrimSpace(realType) != "void" { 534 a, err = types.CastExpr(p, a, argTypes[i], realType) 535 536 if p.AddMessage(p.GenerateWarningMessage(err, n)) { 537 a = util.NewNil() 538 } 539 } 540 } 541 } 542 } 543 } 544 545 if strings.Contains(realType, "...") { 546 p.AddMessage(p.GenerateWarningMessage( 547 fmt.Errorf("not acceptable type '...'"), n)) 548 } 549 550 if a == nil { 551 return nil, "", preStmts, postStmts, 552 fmt.Errorf("argument is nil in function : %s", functionName) 553 } 554 555 if len(functionDef.ArgumentTypes) > i { 556 if !types.IsPointer(functionDef.ArgumentTypes[i], p) { 557 if strings.HasPrefix(functionDef.ArgumentTypes[i], "union ") { 558 a = &goast.CallExpr{ 559 Fun: &goast.SelectorExpr{ 560 X: a, 561 Sel: goast.NewIdent("copy"), 562 }, 563 Lparen: 1, 564 } 565 } 566 } 567 } 568 569 realArgs = append(realArgs, a) 570 } 571 } 572 573 // Added for support removing function `free` of <stdlib.h> 574 // Example of C code: 575 // free(i+=4,buffer) 576 // Example of result Go code: 577 // i += 4 578 // _ = buffer 579 if functionDef.Substitution == "_" { 580 devNull := &goast.AssignStmt{ 581 Lhs: []goast.Expr{goast.NewIdent("_")}, 582 Tok: token.ASSIGN, 583 Rhs: []goast.Expr{realArgs[0]}, 584 } 585 preStmts = append(preStmts, devNull) 586 return nil, n.Type, preStmts, postStmts, nil 587 } 588 589 return util.NewCallExpr(functionName, realArgs...), 590 functionDef.ReturnType, preStmts, postStmts, nil 591 } 592 593 func findAndReplaceUnaryExprOrTypeTraitExpr(node *ast.Node) ( 594 unary ast.Node, tree ast.Node, back func(), err error) { 595 596 defer func() { 597 if err != nil { 598 err = fmt.Errorf("cannot findAndReplaceUnaryExprOrTypeTraitExpr: err = %v", err) 599 if (*node) != nil { 600 err = fmt.Errorf("code line: %d. %v", (*node).Position().Line, err) 601 } 602 } 603 }() 604 605 var counter int 606 var lastNode *ast.Node 607 one := &ast.IntegerLiteral{Type: "int", Value: "1"} 608 609 var searcher func(*ast.Node) bool 610 replacer := func(node *ast.Node) { 611 unary = *node 612 lastNode = node 613 *node = one 614 counter++ 615 } 616 searcher = func(node *ast.Node) (modify bool) { 617 // find 618 if u, ok := (*node).(*ast.UnaryExprOrTypeTraitExpr); ok && 619 u.Function == "sizeof" { 620 return true 621 } 622 for i := range (*node).Children() { 623 if searcher(&((*node).Children()[i])) { 624 replacer(&((*node).Children()[i])) 625 } 626 } 627 return false 628 } 629 if searcher(node) { 630 unary = *node 631 lastNode = node 632 *node = one 633 counter++ 634 } 635 636 back = func() { 637 // return back node 638 if unary != nil { 639 *lastNode = unary 640 } 641 } 642 643 if counter != 1 { 644 err = fmt.Errorf("counter is not 1: %d", counter) 645 return 646 } 647 if unary == nil { 648 err = fmt.Errorf("pointer is nil") 649 return 650 } 651 652 tree = *node 653 654 return 655 } 656 657 // calloc nodes: 658 // [0] - function identification 659 // [1] - expression 660 // [2] - type UnaryExprOrTypeTraitExpr always 661 func transpileCallExprCalloc(expression ast.Node, unary *ast.UnaryExprOrTypeTraitExpr, p *program.Program) ( 662 expr *goast.CallExpr, resultType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { 663 defer func() { 664 if err != nil { 665 err = fmt.Errorf("function: calloc. err = %v", err) 666 } 667 }() 668 669 size, _, newPre, newPost, err := atomicOperation(expression, p) 670 if err != nil { 671 return 672 } 673 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 674 675 var t string = unary.Type2 676 if t == "" { 677 _, t, _, _, _ = transpileToExpr(unary, p, false) 678 } 679 resultType = t + "*" 680 t, err = types.ResolveType(p, t) 681 if err != nil { 682 return nil, "", nil, nil, err 683 } 684 goType := &goast.ArrayType{Elt: goast.NewIdent(t)} 685 686 return util.NewCallExpr("make", goType, size), 687 resultType, preStmts, postStmts, nil 688 } 689 690 func transpileCallExprQsort(n *ast.CallExpr, p *program.Program) ( 691 expr *goast.CallExpr, resultType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { 692 defer func() { 693 if err != nil { 694 err = fmt.Errorf("function: qsort. err = %v", err) 695 } 696 if resultType == "" { 697 resultType = n.Type 698 } 699 }() 700 // CallExpr 0x2c6b1b0 'void' 701 // |-ImplicitCastExpr 'void (*)(void *, size_t, size_t, __compar_fn_t)' <FunctionToPointerDecay> 702 // | `-DeclRefExpr 'void (void *, size_t, size_t, __compar_fn_t)' Function 0x2bec110 'qsort' 'void (void *, size_t, size_t, __compar_fn_t)' 703 // |-ImplicitCastExpr 'void *' <BitCast> 704 // | `-ImplicitCastExpr 'int *' <ArrayToPointerDecay> 705 // | `-DeclRefExpr 'int [6]' lvalue Var 0x2c6a6c0 'values' 'int [6]' 706 // |-ImplicitCastExpr 'size_t':'unsigned long' <IntegralCast> 707 // | `-IntegerLiteral 'int' 6 708 // |-UnaryExprOrTypeTraitExpr 'unsigned long' sizeof 'int' 709 // `-ImplicitCastExpr 'int (*)(const void *, const void *)' <FunctionToPointerDecay> 710 // `-DeclRefExpr 'int (const void *, const void *)' Function 0x2c6aa70 'compare' 'int (const void *, const void *)' 711 // 712 // CallExpr 'void' 713 // |-ImplicitCastExpr 'void (*)(void *, size_t, size_t, __compar_fn_t)' <FunctionToPointerDecay> 714 // | `-DeclRefExpr 'void (void *, size_t, size_t, __compar_fn_t)' Function 0x361b6d0 'qsort' 'void (void *, size_t, size_t, __compar_fn_t)' 715 // |-ImplicitCastExpr 'void *' <BitCast> 716 // | `-ImplicitCastExpr 'int *' <LValueToRValue> 717 // | `-DeclRefExpr 'int *' lvalue ParmVar 0x3668088 'id' 'int *' 718 // |-ImplicitCastExpr 'size_t':'unsigned long' <IntegralCast> 719 // | `-ImplicitCastExpr 'int' <LValueToRValue> 720 // | `-DeclRefExpr 'int' lvalue Var 0x36684e0 'nid' 'int' 721 // |-UnaryExprOrTypeTraitExpr 'unsigned long' sizeof 722 // | `-ParenExpr 'int' lvalue 723 // | `-ArraySubscriptExpr 'int' lvalue 724 // | |-ImplicitCastExpr 'int *' <LValueToRValue> 725 // | | `-DeclRefExpr 'int *' lvalue ParmVar 0x3668088 'id' 'int *' 726 // | `-IntegerLiteral 'int' 0 727 // `-ImplicitCastExpr '__compar_fn_t':'int (*)(const void *, const void *)' <BitCast> 728 // `-CStyleCastExpr 'void *' <BitCast> 729 // `-ImplicitCastExpr 'int (*)(void *, void *)' <FunctionToPointerDecay> 730 // `-DeclRefExpr 'int (void *, void *)' Function 0x3665148 'intcmp' 'int (void *, void *)' 731 // 732 733 arr, _, newPre, newPost, err := atomicOperation(n.Children()[1], p) 734 if err != nil { 735 err = fmt.Errorf("cannot transpile array node: %v", err) 736 return nil, "", nil, nil, err 737 } 738 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 739 740 t, ok := ast.GetTypeIfExist(n.Children()[1].Children()[0]) 741 if !ok { 742 err = fmt.Errorf("cannot take type array node") 743 return nil, "", nil, nil, err 744 } 745 746 *t = strings.Replace(*t, "*", "", 1) 747 748 arrType, err := types.ResolveType(p, *t) 749 if err != nil { 750 err = fmt.Errorf("cannot resolve array type: %v", err) 751 return nil, "", nil, nil, err 752 } 753 754 size, sizeType, newPre, newPost, err := atomicOperation(n.Children()[2], p) 755 if err != nil { 756 err = fmt.Errorf("cannot transpile size node: %v", err) 757 return nil, "", nil, nil, err 758 } 759 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 760 761 size, err = types.CastExpr(p, size, sizeType, "int") 762 if err != nil { 763 err = fmt.Errorf("cannot cast size node to int : %v", err) 764 return nil, "", nil, nil, err 765 } 766 767 f, _, newPre, newPost, err := atomicOperation(n.Children()[4], p) 768 if err != nil { 769 err = fmt.Errorf("cannot transpile function node: %v", err) 770 return nil, "", nil, nil, err 771 } 772 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 773 774 // cast from `int (void *, void *)` to `bool (int, int)` 775 776 valA := CreateSliceFromReference(arrType, &goast.IndexExpr{ 777 X: arr, 778 Lbrack: 1, 779 Index: goast.NewIdent("a"), 780 }) 781 valB := CreateSliceFromReference(arrType, &goast.IndexExpr{ 782 X: arr, 783 Lbrack: 1, 784 Index: goast.NewIdent("b"), 785 }) 786 f = &goast.FuncLit{ 787 Type: &goast.FuncType{ 788 Params: &goast.FieldList{ 789 List: []*goast.Field{ 790 { 791 Names: []*goast.Ident{goast.NewIdent("a"), goast.NewIdent("b")}, 792 Type: goast.NewIdent("int"), 793 }, 794 }, 795 }, 796 Results: &goast.FieldList{ 797 List: []*goast.Field{ 798 {Type: goast.NewIdent("bool")}, 799 }, 800 }, 801 }, 802 Body: &goast.BlockStmt{ 803 List: []goast.Stmt{ 804 &goast.ReturnStmt{ 805 Results: []goast.Expr{ 806 &goast.BinaryExpr{ 807 X: &goast.CallExpr{ 808 Fun: f, 809 Args: []goast.Expr{ 810 valA, 811 valB, 812 }, 813 }, 814 Op: token.LEQ, // <= 815 Y: goast.NewIdent("0"), 816 }, 817 }, 818 }, 819 }, 820 }, 821 } 822 823 p.AddImport("sort") 824 825 return util.NewCallExpr("sort.SliceStable", 826 &goast.SliceExpr{ 827 X: arr, 828 High: size, 829 }, 830 f, 831 ), "", preStmts, postStmts, nil 832 833 } 834 835 func transpileCallExprBsearch(n *ast.CallExpr, p *program.Program) ( 836 expr *goast.CallExpr, resultType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { 837 defer func() { 838 if err != nil { 839 err = fmt.Errorf("function: bsearch. err = %v", err) 840 } 841 if resultType == "" { 842 resultType = n.Type 843 } 844 }() 845 846 key, _, newPre, newPost, err := atomicOperation(n.Children()[1], p) 847 if err != nil { 848 err = fmt.Errorf("cannot transpile key node: %v", err) 849 return nil, "", nil, nil, err 850 } 851 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 852 853 arr, _, newPre, newPost, err := atomicOperation(n.Children()[2], p) 854 if err != nil { 855 err = fmt.Errorf("cannot transpile array node: %v", err) 856 return nil, "", nil, nil, err 857 } 858 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 859 860 t, ok := ast.GetTypeIfExist(n.Children()[2].Children()[0]) 861 if !ok { 862 err = fmt.Errorf("cannot take type array node") 863 return nil, "", nil, nil, err 864 } 865 866 *t = strings.Replace(*t, "*", "", 1) 867 868 arrType, err := types.ResolveType(p, *t) 869 if err != nil { 870 err = fmt.Errorf("cannot resolve array type: %v", err) 871 return nil, "", nil, nil, err 872 } 873 874 size, sizeType, newPre, newPost, err := atomicOperation(n.Children()[3], p) 875 if err != nil { 876 err = fmt.Errorf("cannot transpile size node: %v", err) 877 return nil, "", nil, nil, err 878 } 879 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 880 881 size, err = types.CastExpr(p, size, sizeType, "int") 882 if err != nil { 883 err = fmt.Errorf("cannot cast size node to int : %v", err) 884 return nil, "", nil, nil, err 885 } 886 887 f, _, newPre, newPost, err := atomicOperation(n.Children()[5], p) 888 if err != nil { 889 err = fmt.Errorf("cannot transpile function node: %v", err) 890 return nil, "", nil, nil, err 891 } 892 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 893 894 // cast from `int (void *, void *)` to `bool (int, int)` 895 896 // TODO: Generate missing handle 897 p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("TODO: missing second variable to handle nil cast interface{}"), n)) 898 899 val := CreateSliceFromReference(arrType, &goast.IndexExpr{ 900 X: arr, 901 Lbrack: 1, 902 Index: goast.NewIdent("a"), 903 }) 904 res := CreateSliceFromReference(arrType, &goast.IndexExpr{ 905 X: arr, 906 Lbrack: 1, 907 Index: goast.NewIdent("index"), 908 }) 909 910 f = &goast.FuncLit{ 911 Type: &goast.FuncType{ 912 Params: &goast.FieldList{ 913 List: []*goast.Field{ 914 { 915 Names: []*goast.Ident{goast.NewIdent("a")}, 916 Type: goast.NewIdent("int"), 917 }, 918 }, 919 }, 920 Results: &goast.FieldList{ 921 List: []*goast.Field{ 922 {Type: goast.NewIdent("int")}, 923 }, 924 }, 925 }, 926 Body: &goast.BlockStmt{ 927 List: []goast.Stmt{ 928 &goast.ReturnStmt{ 929 Results: []goast.Expr{ 930 &goast.CallExpr{ 931 Fun: goast.NewIdent("int"), 932 Args: []goast.Expr{ 933 &goast.CallExpr{ 934 Fun: f, 935 Args: []goast.Expr{ 936 val, 937 goast.Expr(key), 938 }, 939 }, 940 }, 941 }, 942 }, 943 }, 944 }, 945 }, 946 } 947 948 fGetIndex := &goast.FuncLit{ 949 Type: &goast.FuncType{ 950 Params: &goast.FieldList{ 951 List: []*goast.Field{ 952 { 953 Names: []*goast.Ident{goast.NewIdent("index")}, 954 Type: goast.NewIdent("int"), 955 }, 956 }, 957 }, 958 Results: &goast.FieldList{ 959 List: []*goast.Field{ 960 {Type: goast.NewIdent("interface{}")}, 961 }, 962 }, 963 }, 964 Body: &goast.BlockStmt{ 965 List: []goast.Stmt{ 966 &goast.ReturnStmt{ 967 Results: []goast.Expr{ 968 res, 969 }, 970 }, 971 }, 972 }, 973 } 974 975 p.AddImport("github.com/Konstantin8105/c4go/noarch") 976 977 return util.NewCallExpr("noarch.BSearch", 978 // sort.Search expecting a "int" type 979 &goast.CallExpr{ 980 Fun: goast.NewIdent("int"), 981 Args: []goast.Expr{size}, 982 }, 983 f, 984 fGetIndex, 985 ), "", preStmts, postStmts, nil 986 987 }