github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/transpiler/binary.go (about) 1 // This file contains functions for transpiling binary operator expressions. 2 3 package transpiler 4 5 import ( 6 "fmt" 7 goast "go/ast" 8 "go/token" 9 "strings" 10 11 "github.com/Konstantin8105/c4go/ast" 12 "github.com/Konstantin8105/c4go/program" 13 "github.com/Konstantin8105/c4go/types" 14 "github.com/Konstantin8105/c4go/util" 15 ) 16 17 // Comma problem. Example: 18 // for (int i=0,j=0;i+=1,j<5;i++,j++){...} 19 // For solving - we have to separate the 20 // binary operator "," to 2 parts: 21 // part 1(pre ): left part - typically one or more some expressions 22 // part 2(stmt): right part - always only one expression, with or without 23 // 24 // logical operators like "==", "!=", ... 25 func transpileBinaryOperatorComma(n *ast.BinaryOperator, p *program.Program) ( 26 stmt goast.Stmt, preStmts []goast.Stmt, err error) { 27 defer func() { 28 if err != nil { 29 err = fmt.Errorf("cannot transpile operator comma : err = %v", err) 30 p.AddMessage(p.GenerateWarningMessage(err, n)) 31 } 32 }() 33 34 left, err := transpileToStmts(n.Children()[0], p) 35 if err != nil { 36 return nil, nil, err 37 } 38 39 right, err := transpileToStmts(n.Children()[1], p) 40 if err != nil { 41 return nil, nil, err 42 } 43 44 if left == nil || right == nil { 45 return nil, nil, 46 fmt.Errorf("cannot transpile binary operator comma: right = %v , left = %v", 47 right, left) 48 } 49 50 preStmts = append(preStmts, left...) 51 preStmts = append(preStmts, right...) 52 53 if len(preStmts) >= 2 { 54 return preStmts[len(preStmts)-1], preStmts[:len(preStmts)-1], nil 55 } 56 57 if len(preStmts) == 1 { 58 return preStmts[0], nil, nil 59 } 60 return nil, nil, nil 61 } 62 63 func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsStmt bool) ( 64 expr goast.Expr, eType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { 65 defer func() { 66 if err != nil { 67 err = fmt.Errorf( 68 "cannot transpile BinaryOperator with type '%s' :"+ 69 " result type = {%s}. Error: %v", n.Type, eType, err) 70 p.AddMessage(p.GenerateWarningMessage(err, n)) 71 } 72 }() 73 74 operator := getTokenForOperatorNoError(n.Operator) 75 n.Type = util.GenerateCorrectType(n.Type) 76 n.Type2 = util.GenerateCorrectType(n.Type2) 77 78 defer func() { 79 if err != nil { 80 err = fmt.Errorf("operator is `%v`. %v", operator, err) 81 } 82 }() 83 84 // Char overflow 85 // BinaryOperator 'int' '!=' 86 // |-ImplicitCastExpr 'int' <IntegralCast> 87 // | `-ImplicitCastExpr 'char' <LValueToRValue> 88 // | `-... 89 // `-ParenExpr 'int' 90 // `-UnaryOperator 'int' prefix '-' 91 // `-IntegerLiteral 'int' 1 92 if n.Operator == "!=" { 93 var leftOk bool 94 if l0, ok := n.ChildNodes[0].(*ast.ImplicitCastExpr); ok && l0.Type == "int" { 95 if len(l0.ChildNodes) > 0 { 96 if l1, ok := l0.ChildNodes[0].(*ast.ImplicitCastExpr); ok && l1.Type == "char" { 97 leftOk = true 98 } 99 } 100 } 101 if leftOk { 102 if r0, ok := n.ChildNodes[1].(*ast.ParenExpr); ok && r0.Type == "int" { 103 if len(r0.ChildNodes) > 0 { 104 if r1, ok := r0.ChildNodes[0].(*ast.UnaryOperator); ok && r1.IsPrefix && r1.Operator == "-" { 105 if r2, ok := r1.ChildNodes[0].(*ast.IntegerLiteral); ok && r2.Type == "int" { 106 r0.ChildNodes[0] = &ast.BinaryOperator{ 107 Type: "int", 108 Type2: "int", 109 Operator: "+", 110 ChildNodes: []ast.Node{ 111 r1, 112 &ast.IntegerLiteral{ 113 Type: "int", 114 Value: "256", 115 }, 116 }, 117 } 118 } 119 } 120 } 121 } 122 } 123 } 124 125 // Example of C code 126 // a = b = 1 127 // // Operation equal transpile from right to left 128 // Solving: 129 // b = 1, a = b 130 // // Operation comma transpile from left to right 131 // If we have for example: 132 // a = b = c = 1 133 // then solution is: 134 // c = 1, b = c, a = b 135 // |-----------| 136 // this part, created in according to 137 // recursive working 138 // Example of AST tree for problem: 139 // |-BinaryOperator 0x2f17870 <line:13:2, col:10> 'int' '=' 140 // | |-DeclRefExpr 0x2f177d8 <col:2> 'int' lvalue Var 0x2f176d8 'x' 'int' 141 // | `-BinaryOperator 0x2f17848 <col:6, col:10> 'int' '=' 142 // | |-DeclRefExpr 0x2f17800 <col:6> 'int' lvalue Var 0x2f17748 'y' 'int' 143 // | `-IntegerLiteral 0x2f17828 <col:10> 'int' 1 144 // 145 // Example of AST tree for solution: 146 // |-BinaryOperator 0x368e8d8 <line:13:2, col:13> 'int' ',' 147 // | |-BinaryOperator 0x368e820 <col:2, col:6> 'int' '=' 148 // | | |-DeclRefExpr 0x368e7d8 <col:2> 'int' lvalue Var 0x368e748 'y' 'int' 149 // | | `-IntegerLiteral 0x368e800 <col:6> 'int' 1 150 // | `-BinaryOperator 0x368e8b0 <col:9, col:13> 'int' '=' 151 // | |-DeclRefExpr 0x368e848 <col:9> 'int' lvalue Var 0x368e6d8 'x' 'int' 152 // | `-ImplicitCastExpr 0x368e898 <col:13> 'int' <LValueToRValue> 153 // | `-DeclRefExpr 0x368e870 <col:13> 'int' lvalue Var 0x368e748 'y' 'int' 154 // 155 // Example 156 // BinaryOperator 'const char *' '=' 157 // |-... 158 // `-ImplicitCastExpr 'const char *' <BitCast> 159 // `-BinaryOperator 'char *' '=' 160 // |-... 161 // `-... 162 if getTokenForOperatorNoError(n.Operator) == token.ASSIGN { 163 child := n.Children()[1] 164 if impl, ok := child.(*ast.ImplicitCastExpr); ok { 165 child = impl.Children()[0] 166 } 167 switch c := child.(type) { 168 case *ast.BinaryOperator: 169 if getTokenForOperatorNoError(c.Operator) == token.ASSIGN { 170 bSecond := ast.BinaryOperator{ 171 Type: c.Type, 172 Operator: "=", 173 } 174 bSecond.AddChild(n.Children()[0]) 175 176 var impl ast.ImplicitCastExpr 177 impl.Type = c.Type 178 impl.Kind = "LValueToRValue" 179 impl.AddChild(c.Children()[0]) 180 bSecond.AddChild(&impl) 181 182 var bComma ast.BinaryOperator 183 bComma.Operator = "," 184 bComma.Type = c.Type 185 bComma.AddChild(c) 186 bComma.AddChild(&bSecond) 187 188 // exprIsStmt now changes to false to stop any AST children from 189 // not being safely wrapped in a closure. 190 return transpileBinaryOperator(&bComma, p, false) 191 } 192 } 193 } 194 195 // Example of C code 196 // a = 1, b = a 197 // Solving 198 // a = 1; // preStmts 199 // b = a; // n 200 // Example of AST tree for problem: 201 // |-BinaryOperator 0x368e8d8 <line:13:2, col:13> 'int' ',' 202 // | |-BinaryOperator 0x368e820 <col:2, col:6> 'int' '=' 203 // | | |-DeclRefExpr 0x368e7d8 <col:2> 'int' lvalue Var 0x368e748 'y' 'int' 204 // | | `-IntegerLiteral 0x368e800 <col:6> 'int' 1 205 // | `-BinaryOperator 0x368e8b0 <col:9, col:13> 'int' '=' 206 // | |-DeclRefExpr 0x368e848 <col:9> 'int' lvalue Var 0x368e6d8 'x' 'int' 207 // | `-ImplicitCastExpr 0x368e898 <col:13> 'int' <LValueToRValue> 208 // | `-DeclRefExpr 0x368e870 <col:13> 'int' lvalue Var 0x368e748 'y' 'int' 209 // 210 // Example of AST tree for solution: 211 // |-BinaryOperator 0x21a7820 <line:13:2, col:6> 'int' '=' 212 // | |-DeclRefExpr 0x21a77d8 <col:2> 'int' lvalue Var 0x21a7748 'y' 'int' 213 // | `-IntegerLiteral 0x21a7800 <col:6> 'int' 1 214 // |-BinaryOperator 0x21a78b0 <line:14:2, col:6> 'int' '=' 215 // | |-DeclRefExpr 0x21a7848 <col:2> 'int' lvalue Var 0x21a76d8 'x' 'int' 216 // | `-ImplicitCastExpr 0x21a7898 <col:6> 'int' <LValueToRValue> 217 // | `-DeclRefExpr 0x21a7870 <col:6> 'int' lvalue Var 0x21a7748 'y' 'int' 218 if getTokenForOperatorNoError(n.Operator) == token.COMMA { 219 stmts, _, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false) 220 if err != nil { 221 err = fmt.Errorf("cannot transpile expr `token.COMMA` child 0. %v", err) 222 return nil, "unknown50", nil, nil, err 223 } 224 preStmts = append(preStmts, newPre...) 225 preStmts = append(preStmts, util.NewExprStmt(stmts)) 226 preStmts = append(preStmts, newPost...) 227 228 var st string 229 stmts, st, newPre, newPost, err = transpileToExpr(n.Children()[1], p, false) 230 if err != nil { 231 err = fmt.Errorf("cannot transpile expr `token.COMMA` child 1. %v", err) 232 return nil, "unknown51", nil, nil, err 233 } 234 // Theoretically , we don't have any preStmts or postStmts 235 // from n.Children()[1] 236 if len(newPre) > 0 || len(newPost) > 0 { 237 p.AddMessage(p.GenerateWarningMessage( 238 fmt.Errorf("not support length pre or post stmts: {%d,%d}", 239 len(newPre), len(newPost)), n)) 240 } 241 return stmts, st, preStmts, postStmts, nil 242 } 243 244 // pointer arithmetic 245 if types.IsPointer(n.Type, p) { 246 if operator == token.ADD || // + 247 false { 248 249 // not acceptable binaryOperator with operator `-` 250 haveSub := false 251 { 252 var check func(ast.Node) 253 check = func(node ast.Node) { 254 if node == nil { 255 return 256 } 257 if bin, ok := node.(*ast.BinaryOperator); ok && bin.Operator == "-" { 258 haveSub = true 259 } 260 for i := range node.Children() { 261 check(node.Children()[i]) 262 } 263 } 264 check(n) 265 } 266 267 if !haveSub { 268 269 fakeUnary := &ast.UnaryOperator{ 270 Type: n.Type, 271 Operator: "*", 272 ChildNodes: []ast.Node{ 273 n, 274 }, 275 } 276 277 var newPre, newPost []goast.Stmt 278 expr, eType, newPre, newPost, err = 279 transpilePointerArith(fakeUnary, p) 280 eType = n.Type 281 282 if err != nil { 283 return 284 } 285 if expr == nil { 286 return nil, "", nil, nil, fmt.Errorf("expr is nil") 287 } 288 preStmts, postStmts = 289 combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 290 291 if ind, ok := expr.(*goast.IndexExpr); ok { 292 expr = &goast.SliceExpr{ 293 X: ind.X, 294 Low: ind.Index, 295 Slice3: false, 296 } 297 } 298 299 return 300 } 301 } 302 } 303 304 left, leftType, newPre, newPost, err := atomicOperation(n.Children()[0], p) 305 if err != nil { 306 err = fmt.Errorf("cannot atomic for left part. %v", err) 307 return nil, "unknown52", nil, nil, err 308 } 309 310 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 311 312 right, rightType, newPre, newPost, err := atomicOperation(n.Children()[1], p) 313 if err != nil { 314 err = fmt.Errorf("cannot atomic for right part. %v", err) 315 return nil, "unknown53", nil, nil, err 316 } 317 318 if types.IsPointer(leftType, p) && types.IsPointer(rightType, p) { 319 switch operator { 320 case token.SUB: // - 321 p.AddImport("unsafe") 322 var sizeof int 323 sizeof, err = types.SizeOf(p, types.GetBaseType(leftType)) 324 if err != nil { 325 return nil, "PointerOperation_unknown01", nil, nil, err 326 } 327 var e goast.Expr 328 var newPost []goast.Stmt 329 e, newPost, err = SubTwoPnts(p, left, leftType, right, rightType, sizeof) 330 if err != nil { 331 return nil, "PointerOperation_unknown02", nil, nil, err 332 } 333 postStmts = append(postStmts, newPost...) 334 335 expr, err = types.CastExpr(p, e, "long long", n.Type) 336 if err != nil { 337 return nil, "PointerOperation_unknown03", nil, nil, err 338 } 339 eType = n.Type 340 return 341 342 case token.GTR, token.GEQ, // > >= 343 token.LOR, // || 344 token.LAND, // && 345 token.LSS, token.LEQ, // < <= 346 token.EQL, token.NEQ: // == != 347 348 // IfStmt 0x2369a68 <line:210:3, line:211:11> 349 // |-BinaryOperator 0x2369a00 <line:210:7, col:21> 'int' '==' 350 // | |-ImplicitCastExpr 0x23699d0 <col:7, col:16> 'struct font *' <LValueToRValue> 351 // | | `-ArraySubscriptExpr 0x2369990 <col:7, col:16> 'struct font *' lvalue 352 // | | |-ImplicitCastExpr 0x2369960 <col:7> 'struct font **' <ArrayToPointerDecay> 353 // | | | `-DeclRefExpr 0x2369920 <col:7> 'struct font *[32]' lvalue Var 0x235fbe8 'fn_font' 'struct font *[32]' 354 // | | `-ImplicitCastExpr 0x2369978 <col:15> 'int' <LValueToRValue> 355 // | | `-DeclRefExpr 0x2369940 <col:15> 'int' lvalue Var 0x2369790 'i' 'int' 356 // | `-ImplicitCastExpr 0x23699e8 <col:21> 'struct font *' <LValueToRValue> 357 // | `-DeclRefExpr 0x23699b0 <col:21> 'struct font *' lvalue ParmVar 0x2369638 'fn' 'struct font *' 358 // `-ReturnStmt 0x2369a58 <line:211:4, col:11> 359 // `-ImplicitCastExpr 0x2369a40 <col:11> 'int' <LValueToRValue> 360 // `-DeclRefExpr 0x2369a20 <col:11> 'int' lvalue Var 0x2369790 'i' 'int' 361 362 var sizeof int 363 baseType := types.GetBaseType(leftType) 364 sizeof, err = types.SizeOf(p, baseType) 365 if err != nil { 366 err = fmt.Errorf("{'%s' %v '%s'}. sizeof = %d for baseType = '%s'. %v", 367 leftType, operator, rightType, sizeof, baseType, err) 368 return nil, "PointerOperation_unknown04", nil, nil, err 369 } 370 var e goast.Expr 371 var newPost []goast.Stmt 372 e, newPost, err = PntCmpPnt( 373 p, 374 left, leftType, 375 right, rightType, 376 sizeof, operator, 377 ) 378 if err != nil { 379 err = fmt.Errorf("{'%s' %v '%s'}. for base type: `%s`. %v", 380 leftType, operator, rightType, baseType, err) 381 return nil, "PointerOperation_unknown05", nil, nil, err 382 } 383 postStmts = append(postStmts, newPost...) 384 expr = e 385 eType = "bool" 386 387 return 388 389 case token.ASSIGN: // = 390 // ignore 391 392 default: 393 err = fmt.Errorf("not implemented pointer operation: %v", operator) 394 return 395 } 396 } 397 398 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 399 400 returnType := types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType) 401 402 if operator == token.LAND || operator == token.LOR { // && || 403 left, err = types.CastExpr(p, left, leftType, "bool") 404 if err != nil { 405 p.AddMessage(p.GenerateWarningMessage(err, n)) 406 // ignore error 407 left = util.NewNil() 408 err = nil 409 } 410 411 right, err = types.CastExpr(p, right, rightType, "bool") 412 if err != nil { 413 p.AddMessage(p.GenerateWarningMessage(err, n)) 414 // ignore error 415 right = util.NewNil() 416 err = nil 417 } 418 419 resolvedLeftType, err := types.ResolveType(p, leftType) 420 if err != nil { 421 p.AddMessage(p.GenerateWarningMessage(err, n)) 422 } 423 424 expr := util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt) 425 426 return expr, "bool", preStmts, postStmts, nil 427 } 428 429 // The right hand argument of the shift left or shift right operators 430 // in Go must be unsigned integers. In C, shifting with a negative shift 431 // count is undefined behaviour (so we should be able to ignore that case). 432 // To handle this, cast the shift count to a uint64. 433 if operator == token.SHL || // << 434 operator == token.SHR || // >> 435 operator == token.SHL_ASSIGN || // <<= 436 operator == token.SHR_ASSIGN || // <<= 437 false { 438 right, err = types.CastExpr(p, right, rightType, "unsigned long long") 439 p.AddMessage(p.GenerateWarningMessage(err, n)) 440 if right == nil { 441 right = util.NewNil() 442 } 443 } 444 445 // pointer arithmetic 446 if types.IsPointer(n.Type, p) { 447 if operator == token.ADD || // + 448 operator == token.SUB || // - 449 false { 450 451 el, extl, prel, postl, errl := atomicOperation(n.Children()[0], p) 452 er, extr, prer, postr, errr := atomicOperation(n.Children()[1], p) 453 if errl != nil || errr != nil { 454 err = fmt.Errorf("pointer operation is not valid : %v. %v", errl, errr) 455 return 456 } 457 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, prel, postl) 458 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, prer, postr) 459 460 if types.IsCPointer(extl, p) { 461 expr, eType, prel, postl, errl = pointerArithmetic(p, el, extl, er, extr, operator) 462 } else { 463 expr, eType, prel, postl, errl = pointerArithmetic(p, er, extr, el, extl, operator) 464 } 465 466 if errl != nil { 467 err = fmt.Errorf("pointer operation is not valid : %v", errl) 468 return 469 } 470 471 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, prel, postl) 472 473 return 474 } 475 } 476 477 if operator == token.NEQ || // != 478 operator == token.EQL || // == 479 operator == token.LSS || // < 480 operator == token.GTR || // > 481 operator == token.AND || // & 482 operator == token.ADD || // + 483 operator == token.SUB || // - 484 operator == token.MUL || // * 485 operator == token.QUO || // / 486 operator == token.REM || // % 487 operator == token.LEQ || // <= 488 operator == token.GEQ || // >= 489 operator == token.ADD_ASSIGN || // += 490 operator == token.SUB_ASSIGN || // -= 491 operator == token.MUL_ASSIGN || // *= 492 operator == token.QUO_ASSIGN || // /= 493 operator == token.REM_ASSIGN || // %= 494 495 operator == token.AND_ASSIGN || // &= 496 operator == token.OR_ASSIGN || // |= 497 operator == token.XOR_ASSIGN || // ^= 498 operator == token.SHL_ASSIGN || // <<= 499 operator == token.SHR_ASSIGN || // >>= 500 operator == token.AND_NOT_ASSIGN || // &^= 501 false { 502 503 if rightType == types.NullPointer && leftType == types.NullPointer { 504 // example C code : 505 // if ( NULL == NULL ) 506 right = goast.NewIdent("1") 507 rightType = "int" 508 left = goast.NewIdent("1") 509 leftType = "int" 510 511 } else if rightType != types.NullPointer && leftType != types.NullPointer { 512 // We may have to cast the right side to the same type as the left 513 // side. This is a bit crude because we should make a better 514 // decision of which type to cast to instead of only using the type 515 // of the left side. 516 517 if operator == token.ADD || // + 518 operator == token.SUB || // - 519 operator == token.MUL || // * 520 operator == token.QUO || // / 521 operator == token.REM || // % 522 false { 523 524 if rightType == "bool" { 525 right, err = types.CastExpr(p, right, rightType, "int") 526 rightType = "int" 527 p.AddMessage(p.GenerateWarningMessage(err, n)) 528 } 529 if leftType == "bool" { 530 left, err = types.CastExpr(p, left, leftType, "int") 531 leftType = "int" 532 p.AddMessage(p.GenerateWarningMessage(err, n)) 533 } 534 } 535 right, err = types.CastExpr(p, right, rightType, leftType) 536 rightType = leftType 537 p.AddMessage(p.GenerateWarningMessage(err, n)) 538 539 // compare pointers 540 // 541 // BinaryOperator 'int' '<' 542 // |-ImplicitCastExpr 'char *' <LValueToRValue> 543 // | `-DeclRefExpr 'char *' lvalue Var 0x26ba988 'c' 'char *' 544 // `-ImplicitCastExpr 'char *' <LValueToRValue> 545 // `-DeclRefExpr 'char *' lvalue Var 0x26ba8a8 'b' 'char *' 546 if types.IsPointer(leftType, p) || types.IsPointer(rightType, p) { 547 err = fmt.Errorf("need add pointer operator : %s %v %s", 548 leftType, n.Operator, rightType) 549 return 550 } 551 } 552 } 553 554 if operator == token.ASSIGN { // = 555 556 // BinaryOperator 'double *' '=' 557 // |-DeclRefExpr 'double *' lvalue Var 0x2a7fa48 'd' 'double *' 558 // `-ImplicitCastExpr 'double *' <BitCast> 559 // `-CStyleCastExpr 'char *' <BitCast> 560 // `-... 561 right, err = types.CastExpr(p, right, rightType, returnType) 562 rightType = returnType 563 if err != nil { 564 return 565 } 566 567 if _, ok := right.(*goast.UnaryExpr); ok && types.IsDereferenceType(rightType) { 568 deref, err := types.GetDereferenceType(rightType) 569 570 if !p.AddMessage(p.GenerateWarningMessage(err, n)) { 571 resolvedDeref, err := types.ResolveType(p, deref) 572 573 // FIXME: I'm not sure how this situation arises. 574 if resolvedDeref == "" { 575 resolvedDeref = "interface{}" 576 } 577 578 if !p.AddMessage(p.GenerateWarningMessage(err, n)) { 579 p.AddImport("unsafe") 580 right = CreateSliceFromReference(resolvedDeref, right) 581 } 582 } 583 } 584 585 if p.AddMessage(p.GenerateWarningMessage(err, n)) && right == nil { 586 right = util.NewNil() 587 } 588 } 589 590 var resolvedLeftType = n.Type 591 if !util.IsFunction(n.Type) && !types.IsTypedefFunction(p, n.Type) { 592 if leftType != types.NullPointer { 593 resolvedLeftType, err = types.ResolveType(p, leftType) 594 } else { 595 resolvedLeftType, err = types.ResolveType(p, rightType) 596 } 597 p.AddMessage(p.GenerateWarningMessage(err, n)) 598 } 599 600 // Enum casting 601 if operator != token.ASSIGN && strings.Contains(rightType, "enum ") { 602 right, err = types.CastExpr(p, right, rightType, "int") 603 if err != nil { 604 p.AddMessage(p.GenerateWarningMessage(err, n)) 605 } 606 } 607 608 if left == nil { 609 err = fmt.Errorf("left part of binary operation is nil. left : %#v", n.Children()[0]) 610 p.AddMessage(p.GenerateWarningMessage(err, n)) 611 return nil, "", nil, nil, err 612 } 613 614 if right == nil { 615 err = fmt.Errorf("right part of binary operation is nil. right : %#v", n.Children()[1]) 616 p.AddMessage(p.GenerateWarningMessage(err, n)) 617 return nil, "", nil, nil, err 618 } 619 620 return util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt), 621 types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType), 622 preStmts, postStmts, nil 623 } 624 625 func foundCallExpr(n ast.Node) *ast.CallExpr { 626 switch v := n.(type) { 627 case *ast.ImplicitCastExpr, *ast.CStyleCastExpr: 628 return foundCallExpr(n.Children()[0]) 629 case *ast.CallExpr: 630 return v 631 } 632 return nil 633 }