github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/transpiler/branch.go (about) 1 // This file contains functions for transpiling common branching and control 2 // flow, such as "if", "while", "do" and "for". The more complicated control 3 // flows like "switch" will be put into their own file of the same or sensible 4 // name. 5 6 package transpiler 7 8 import ( 9 "fmt" 10 "go/token" 11 12 "github.com/Konstantin8105/c4go/ast" 13 "github.com/Konstantin8105/c4go/program" 14 "github.com/Konstantin8105/c4go/types" 15 "github.com/Konstantin8105/c4go/util" 16 17 goast "go/ast" 18 ) 19 20 func transpileIfStmt(n *ast.IfStmt, p *program.Program) ( 21 _ *goast.IfStmt, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { 22 23 defer func() { 24 if err != nil { 25 err = fmt.Errorf("cannot transpileIfStmt. %v", err) 26 } 27 }() 28 29 children := n.Children() 30 31 // There is always 4 or 5 children in an IfStmt. For example: 32 // 33 // if (i == 0) { 34 // return 0; 35 // } else { 36 // return 1; 37 // } 38 // 39 // 1. Not sure what this is for. This gets removed. 40 // 2. Not sure what this is for. 41 // 3. conditional = BinaryOperator: i == 0 42 // 4. body = CompoundStmt: { return 0; } 43 // 5. elseBody = CompoundStmt: { return 1; } 44 // 45 // elseBody will be nil if there is no else clause. 46 47 // On linux I have seen only 4 children for an IfStmt with the same 48 // definitions above, but missing the first argument. Since we don't 49 // know what the first argument is for anyway we will just remove it on 50 // Mac if necessary. 51 if len(children) == 5 && children[0] != nil { 52 panic("non-nil child 0 in IfStmt") 53 } 54 if len(children) == 5 { 55 children = children[1:] 56 } 57 58 // From here on there must be 4 children. 59 if len(children) != 4 { 60 children = append([]ast.Node{nil}, children...) 61 } 62 if len(children) != 4 { 63 children = append(children, nil) 64 } 65 66 // Maybe we will discover what the nil value is? 67 if children[0] != nil { 68 panic("non-nil child 0 in IfStmt") 69 } 70 71 // The last parameter must be false because we are transpiling an 72 // expression - assignment operators need to be wrapped in closures. 73 conditional, conditionalType, newPre, newPost, err := atomicOperation(children[1], p) 74 if err != nil { 75 err = fmt.Errorf("cannot transpile for condition. %v", err) 76 return nil, nil, nil, err 77 } 78 // null in C is false 79 if conditionalType == types.NullPointer { 80 conditional = util.NewIdent("false") 81 conditionalType = "bool" 82 } 83 84 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 85 86 // The condition in Go must always be a bool. 87 boolCondition, err := types.CastExpr(p, conditional, conditionalType, "bool") 88 p.AddMessage(p.GenerateWarningMessage(err, n)) 89 90 if boolCondition == nil { 91 boolCondition = util.NewNil() 92 } 93 94 body := new(goast.BlockStmt) 95 96 if children[2] != nil { 97 var newPre, newPost []goast.Stmt 98 body, newPre, newPost, err = transpileToBlockStmt(children[2], p) 99 if err != nil { 100 return nil, nil, nil, err 101 } 102 103 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 104 if body == nil { 105 return nil, nil, nil, fmt.Errorf("body of If cannot by nil") 106 } 107 } 108 109 if boolCondition == nil { 110 return nil, nil, nil, fmt.Errorf("bool Condition in If cannot by nil") 111 } 112 r := &goast.IfStmt{ 113 Cond: boolCondition, 114 Body: body, 115 } 116 117 if children[3] != nil { 118 elseBody, newPre, newPost, err := transpileToBlockStmt(children[3], p) 119 if err != nil { 120 return nil, nil, nil, err 121 } 122 123 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 124 125 if elseBody != nil { 126 r.Else = elseBody 127 if _, ok := children[3].(*ast.IfStmt); ok { 128 if len(elseBody.List) == 1 { 129 r.Else = elseBody.List[0] 130 } 131 } 132 } else { 133 return nil, nil, nil, fmt.Errorf("body of Else in If cannot be nil") 134 } 135 } 136 137 return r, preStmts, postStmts, nil 138 } 139 140 func transpileForStmt(n *ast.ForStmt, p *program.Program) ( 141 f goast.Stmt, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { 142 143 // This `defer` is workaround 144 // Please remove after solving all problems 145 defer func() { 146 if err != nil { 147 err = fmt.Errorf("cannot transpile ForStmt: err = %v", err) 148 p.AddMessage(p.GenerateWarningMessage(err, n)) 149 } 150 }() 151 152 children := n.Children() 153 154 // There are always 5 children in a ForStmt, for example: 155 // 156 // for ( c = 0 ; c < n ; c++ ) { 157 // doSomething(); 158 // } 159 // 160 // 1. initExpression = BinaryStmt: c = 0 161 // 2. Not sure what this is for, but it's always nil. There is a panic 162 // below in case we discover what it is used for (pun intended). 163 // 3. conditionalExpression = BinaryStmt: c < n 164 // 4. stepExpression = BinaryStmt: c++ 165 // 5. body = CompoundStmt: { CallExpr } 166 167 if len(children) != 5 { 168 panic(fmt.Sprintf("Expected 5 children in ForStmt, got %#v", children)) 169 } 170 171 // TODO: The second child of a ForStmt appears to always be null. 172 // Are there any cases where it is used? 173 if children[1] != nil { 174 panic("non-nil child 1 in ForStmt") 175 } 176 177 switch c := children[0].(type) { 178 case *ast.BinaryOperator: 179 if c.Operator == "," { 180 // If we have 2 and more initializations like 181 // in operator for 182 // for( a = 0, b = 0, c = 0; a < 5; a ++) 183 // recursive action to code like that: 184 // a = 0; 185 // b = 0; 186 // for(c = 0 ; a < 5 ; a++) 187 before, newPre, newPost, err := transpileToStmt(children[0], p) 188 if err != nil { 189 err = fmt.Errorf("cannot transpile comma binaryoperator. %v", 190 err) 191 return nil, nil, nil, err 192 } 193 preStmts = append(preStmts, combineStmts(newPre, before, newPost)...) 194 children[0] = c.Children()[1] 195 } 196 case *ast.DeclStmt: 197 { 198 // If we have 2 and more initializations like 199 // in operator for 200 // for(int a = 0, b = 0, c = 0; a < 5; a ++) 201 newPre, err := transpileToStmts(children[0], p) 202 if err != nil { 203 err = fmt.Errorf("cannot transpile with many initialization. %v", 204 err) 205 return nil, nil, nil, err 206 } 207 children[0] = nil 208 preStmts = append(preStmts, newPre...) 209 } 210 } 211 212 init, newPre, newPost, err := transpileToStmt(children[0], p) 213 if err != nil { 214 err = fmt.Errorf("cannot init. %v", err) 215 return nil, nil, nil, err 216 } 217 218 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 219 220 // If we have 2 and more increments 221 // in operator for 222 // for( a = 0; a < 5; a ++, b++, c+=2) 223 switch c := children[3].(type) { 224 case *ast.BinaryOperator: 225 if c.Operator == "," { 226 // recursive action to code like that: 227 // a = 0; 228 // b = 0; 229 // for(a = 0 ; a < 5 ; ){ 230 // body 231 // a++; 232 // b++; 233 // c+=2; 234 // } 235 // 236 var compound *ast.CompoundStmt 237 if children[4] != nil { 238 // if body is exist 239 if _, ok := children[4].(*ast.CompoundStmt); !ok { 240 compound = new(ast.CompoundStmt) 241 compound.AddChild(children[4]) 242 } else { 243 compound = children[4].(*ast.CompoundStmt) 244 } 245 } else { 246 // if body is not exist 247 compound = new(ast.CompoundStmt) 248 } 249 compound.ChildNodes = append( 250 compound.Children(), 251 c.Children()[0:len(c.Children())]...) 252 children[4] = compound 253 children[3] = nil 254 } 255 } 256 257 var post goast.Stmt 258 var transpilate bool 259 if v, ok := children[3].(*ast.UnaryOperator); ok { 260 if vv, ok := v.Children()[0].(*ast.DeclRefExpr); ok { 261 if !types.IsPointer(vv.Type, p) && !util.IsFunction(vv.Type) { 262 switch v.Operator { 263 case "++": 264 // for case: 265 // for(...;...;i++)... 266 post = &goast.IncDecStmt{ 267 X: util.NewIdent(vv.Name), 268 Tok: token.INC, 269 } 270 transpilate = true 271 case "--": 272 // for case: 273 // for(...;...;i--)... 274 post = &goast.IncDecStmt{ 275 X: util.NewIdent(vv.Name), 276 Tok: token.DEC, 277 } 278 transpilate = true 279 } 280 } 281 } 282 } 283 if !transpilate { 284 post, newPre, newPost, err = transpileToStmt(children[3], p) 285 if err != nil { 286 err = fmt.Errorf("cannot transpile children[3] : %v", err) 287 return nil, nil, nil, err 288 } 289 290 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 291 } 292 293 // If we have 2 and more conditions 294 // in operator for 295 // for( a = 0; b = c, b++, a < 5; a ++) 296 switch c := children[2].(type) { 297 case *ast.BinaryOperator: 298 if c.Operator == "," { 299 // recursive action to code like that: 300 // a = 0; 301 // b = 0; 302 // for(a = 0 ; ; c+=2){ 303 // b = c; 304 // b++; 305 // if (!(a < 5)) 306 // break; 307 // body 308 // } 309 tempSlice := c.Children()[0 : len(c.Children())-1] 310 311 var condition ast.IfStmt 312 condition.AddChild(nil) 313 var par ast.ParenExpr 314 par.Type = "bool" 315 par.AddChild(c.Children()[len(c.Children())-1]) 316 var unitary ast.UnaryOperator 317 unitary.Type = "bool" 318 unitary.AddChild(&par) 319 unitary.Operator = "!" 320 condition.AddChild(&unitary) 321 var c ast.CompoundStmt 322 c.AddChild(&ast.BreakStmt{}) 323 condition.AddChild(&c) 324 condition.AddChild(nil) 325 326 tempSlice = append(tempSlice, &condition) 327 328 var compound *ast.CompoundStmt 329 if children[4] != nil { 330 // if body is exist 331 compound = children[4].(*ast.CompoundStmt) 332 } else { 333 // if body is not exist 334 compound = new(ast.CompoundStmt) 335 } 336 compound.ChildNodes = append(tempSlice, compound.Children()...) 337 children[4] = compound 338 children[2] = nil 339 } 340 } 341 342 // The condition can be nil. This means an infinite loop and will be 343 // rendered in Go as "for {". 344 var condition goast.Expr 345 if children[2] != nil { 346 var conditionType string 347 var newPre, newPost []goast.Stmt 348 349 // The last parameter must be false because we are transpiling an 350 // expression - assignment operators need to be wrapped in closures. 351 condition, conditionType, newPre, newPost, err = atomicOperation(children[2], p) 352 if err != nil { 353 return nil, nil, nil, err 354 } 355 // null in C is false 356 if conditionType == types.NullPointer { 357 condition = util.NewIdent("false") 358 conditionType = "bool" 359 } 360 361 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 362 363 condition, err = types.CastExpr(p, condition, conditionType, "bool") 364 p.AddMessage(p.GenerateWarningMessage(err, n)) 365 366 if condition == nil { 367 condition = util.NewNil() 368 } 369 } 370 371 if children[4] == nil { 372 // for case if operator FOR haven't body 373 children[4] = &ast.CompoundStmt{} 374 } 375 body, newPre, newPost, err := transpileToBlockStmt(children[4], p) 376 if err != nil { 377 err = fmt.Errorf("cannot transpile body. %v", err) 378 return nil, nil, nil, err 379 } 380 if body == nil { 381 return nil, nil, nil, fmt.Errorf("body of For cannot be nil") 382 } 383 384 preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) 385 386 // avoid extra block around FOR 387 if len(preStmts) == 0 && len(postStmts) == 0 { 388 return &goast.ForStmt{ 389 Init: init, 390 Cond: condition, 391 Post: post, 392 Body: body, 393 }, preStmts, postStmts, nil 394 } 395 396 // for avoid duplication of init values for 397 // case with 2 for`s 398 var block goast.BlockStmt 399 var forStmt = goast.ForStmt{ 400 Init: init, 401 Cond: condition, 402 Post: post, 403 Body: body, 404 } 405 block.List = combineStmts(preStmts, &forStmt, postStmts) 406 block.Lbrace = 1 407 408 return &block, nil, nil, nil 409 } 410 411 // transpileWhileStmt - transpiler for operator While. 412 // We have only operator FOR in Go, but in C we also have 413 // operator WHILE. So, we have to convert to operator FOR. 414 // We choose directly conversion from AST C code to AST C code, for 415 // - avoid duplicate of code in realization WHILE and FOR. 416 // - create only one operator FOR powerful. 417 // Example of C code with operator WHILE: 418 // 419 // while(i > 0){ 420 // printf("While: %d\n",i); 421 // i--; 422 // } 423 // 424 // AST for that code: 425 // 426 // |-WhileStmt 0x2530a10 <line:6:2, line:9:2> 427 // | |-<<<NULL>>> 428 // | |-BinaryOperator 0x25307f0 <line:6:8, col:12> 'int' '>' 429 // | | |-ImplicitCastExpr 0x25307d8 <col:8> 'int' <LValueToRValue> 430 // | | | `-DeclRefExpr 0x2530790 <col:8> 'int' lvalue Var 0x25306f8 'i' 'int' 431 // | | `-IntegerLiteral 0x25307b8 <col:12> 'int' 0 432 // | `-CompoundStmt 0x25309e8 <col:14, line:9:2> 433 // | |-CallExpr 0x2530920 <line:7:3, col:25> 'int' 434 // | | |-ImplicitCastExpr 0x2530908 <col:3> 'int (*)(const char *, ...)' <FunctionToPointerDecay> 435 // | | | `-DeclRefExpr 0x2530818 <col:3> 'int (const char *, ...)' Function 0x2523ee8 'printf' 'int (const char *, ...)' 436 // | | |-ImplicitCastExpr 0x2530970 <col:10> 'const char *' <BitCast> 437 // | | | `-ImplicitCastExpr 0x2530958 <col:10> 'char *' <ArrayToPointerDecay> 438 // | | | `-StringLiteral 0x2530878 <col:10> 'char [11]' lvalue "While: %d\n" 439 // | | `-ImplicitCastExpr 0x2530988 <col:24> 'int' <LValueToRValue> 440 // | | `-DeclRefExpr 0x25308b0 <col:24> 'int' lvalue Var 0x25306f8 'i' 'int' 441 // | `-UnaryOperator 0x25309c8 <line:8:3, col:4> 'int' postfix '--' 442 // | `-DeclRefExpr 0x25309a0 <col:3> 'int' lvalue Var 0x25306f8 'i' 'int' 443 // 444 // Example of C code with operator FOR: 445 // 446 // for (;i > 0;){ 447 // printf("For: %d\n",i); 448 // i--; 449 // } 450 // 451 // AST for that code: 452 // 453 // |-ForStmt 0x2530d08 <line:11:2, line:14:2> 454 // | |-<<<NULL>>> 455 // | |-<<<NULL>>> 456 // | |-BinaryOperator 0x2530b00 <line:11:8, col:12> 'int' '>' 457 // | | |-ImplicitCastExpr 0x2530ae8 <col:8> 'int' <LValueToRValue> 458 // | | | `-DeclRefExpr 0x2530aa0 <col:8> 'int' lvalue Var 0x25306f8 'i' 'int' 459 // | | `-IntegerLiteral 0x2530ac8 <col:12> 'int' 0 460 // | |-<<<NULL>>> 461 // | `-CompoundStmt 0x2530ce0 <col:15, line:14:2> 462 // | |-CallExpr 0x2530bf8 <line:12:3, col:23> 'int' 463 // | | |-ImplicitCastExpr 0x2530be0 <col:3> 'int (*)(const char *, ...)' <FunctionToPointerDecay> 464 // | | | `-DeclRefExpr 0x2530b28 <col:3> 'int (const char *, ...)' Function 0x2523ee8 'printf' 'int (const char *, ...)' 465 // | | |-ImplicitCastExpr 0x2530c48 <col:10> 'const char *' <BitCast> 466 // | | | `-ImplicitCastExpr 0x2530c30 <col:10> 'char *' <ArrayToPointerDecay> 467 // | | | `-StringLiteral 0x2530b88 <col:10> 'char [9]' lvalue "For: %d\n" 468 // | | `-ImplicitCastExpr 0x2530c60 <col:22> 'int' <LValueToRValue> 469 // | | `-DeclRefExpr 0x2530bb8 <col:22> 'int' lvalue Var 0x25306f8 'i' 'int' 470 // | `-UnaryOperator 0x2530ca0 <line:13:3, col:4> 'int' postfix '--' 471 // | `-DeclRefExpr 0x2530c78 <col:3> 'int' lvalue Var 0x25306f8 'i' 'int' 472 func transpileWhileStmt(n *ast.WhileStmt, p *program.Program) ( 473 goast.Stmt, []goast.Stmt, []goast.Stmt, error) { 474 475 for i := 0; i < len(n.Children()); i++ { 476 if n.ChildNodes[0] == nil { 477 n.ChildNodes = n.ChildNodes[1:] 478 } 479 break 480 } 481 482 var forOperator ast.ForStmt 483 forOperator.AddChild(nil) 484 forOperator.AddChild(nil) 485 forOperator.AddChild(n.Children()[0]) 486 forOperator.AddChild(nil) 487 if len(n.Children()) > 1 { 488 if n.Children()[1] == nil { 489 // added for case if WHILE haven't body, for example: 490 // while(0); 491 n.Children()[1] = &ast.CompoundStmt{} 492 } 493 forOperator.AddChild(n.Children()[1]) 494 } else { 495 forOperator.AddChild(&ast.CompoundStmt{}) 496 } 497 498 return transpileForStmt(&forOperator, p) 499 } 500 501 // transpileDoStmt - transpiler for operator Do...While 502 // We have only operators FOR and IF in Go, but in C we also have 503 // operator DO...WHILE. So, we have to convert to operators FOR and IF. 504 // We choose directly conversion from AST C code to AST C code, for: 505 // - avoid duplicate of code in realization DO...WHILE and FOR. 506 // - create only one powerful operator FOR. 507 // Example of C code with operator DO...WHILE: 508 // 509 // do{ 510 // printf("While: %d\n",i); 511 // i--; 512 // }while(i > 0); 513 // 514 // AST for that code: 515 // 516 // |-DoStmt 0x3bb1a68 <line:7:2, line:10:14> 517 // | |-CompoundStmt 0x3bb19b8 <line:7:4, line:10:2> 518 // | | |-CallExpr 0x3bb18f0 <line:8:3, col:25> 'int' 519 // | | | |-ImplicitCastExpr 0x3bb18d8 <col:3> 'int (*)(const char *, ...)' <FunctionToPointerDecay> 520 // | | | | `-DeclRefExpr 0x3bb17e0 <col:3> 'int (const char *, ...)' Function 0x3ba4ee8 'printf' 'int (const char *, ...)' 521 // | | | |-ImplicitCastExpr 0x3bb1940 <col:10> 'const char *' <BitCast> 522 // | | | | `-ImplicitCastExpr 0x3bb1928 <col:10> 'char *' <ArrayToPointerDecay> 523 // | | | | `-StringLiteral 0x3bb1848 <col:10> 'char [11]' lvalue "While: %d\n" 524 // | | | `-ImplicitCastExpr 0x3bb1958 <col:24> 'int' <LValueToRValue> 525 // | | | `-DeclRefExpr 0x3bb1880 <col:24> 'int' lvalue Var 0x3bb16f8 'i' 'int' 526 // | | `-UnaryOperator 0x3bb1998 <line:9:3, col:4> 'int' postfix '--' 527 // | | `-DeclRefExpr 0x3bb1970 <col:3> 'int' lvalue Var 0x3bb16f8 'i' 'int' 528 // | `-BinaryOperator 0x3bb1a40 <line:10:9, col:13> 'int' '>' 529 // | |-ImplicitCastExpr 0x3bb1a28 <col:9> 'int' <LValueToRValue> 530 // | | `-DeclRefExpr 0x3bb19e0 <col:9> 'int' lvalue Var 0x3bb16f8 'i' 'int' 531 // | `-IntegerLiteral 0x3bb1a08 <col:13> 'int' 0 532 // 533 // Example of C code with operator FOR: 534 // 535 // for(;;){ 536 // printf("For: %d\n",i); 537 // i--; 538 // if(!(i>0)){ 539 // break; 540 // } 541 // } 542 // 543 // AST for that code: 544 // 545 // |-ForStmt 0x3bb1e08 <line:12:2, line:18:2> 546 // | |-<<<NULL>>> 547 // | |-<<<NULL>>> 548 // | |-<<<NULL>>> 549 // | |-<<<NULL>>> 550 // | `-CompoundStmt 0x3bb1dd8 <line:12:9, line:18:2> 551 // | |-CallExpr 0x3bb1bc8 <line:13:3, col:23> 'int' 552 // | | |-ImplicitCastExpr 0x3bb1bb0 <col:3> 'int (*)(const char *, ...)' <FunctionToPointerDecay> 553 // | | | `-DeclRefExpr 0x3bb1af8 <col:3> 'int (const char *, ...)' Function 0x3ba4ee8 'printf' 'int (const char *, ...)' 554 // | | |-ImplicitCastExpr 0x3bb1c18 <col:10> 'const char *' <BitCast> 555 // | | | `-ImplicitCastExpr 0x3bb1c00 <col:10> 'char *' <ArrayToPointerDecay> 556 // | | | `-StringLiteral 0x3bb1b58 <col:10> 'char [9]' lvalue "For: %d\n" 557 // | | `-ImplicitCastExpr 0x3bb1c30 <col:22> 'int' <LValueToRValue> 558 // | | `-DeclRefExpr 0x3bb1b88 <col:22> 'int' lvalue Var 0x3bb16f8 'i' 'int' 559 // | |-UnaryOperator 0x3bb1c70 <line:14:3, col:4> 'int' postfix '--' 560 // | | `-DeclRefExpr 0x3bb1c48 <col:3> 'int' lvalue Var 0x3bb16f8 'i' 'int' 561 // | `-IfStmt 0x3bb1da8 <line:15:3, line:17:3> 562 // | |-<<<NULL>>> 563 // | |-UnaryOperator 0x3bb1d60 <line:15:6, col:11> 'int' prefix '!' 564 // | | `-ParenExpr 0x3bb1d40 <col:7, col:11> 'int' 565 // | | `-BinaryOperator 0x3bb1d18 <col:8, col:10> 'int' '>' 566 // | | |-ImplicitCastExpr 0x3bb1d00 <col:8> 'int' <LValueToRValue> 567 // | | | `-DeclRefExpr 0x3bb1c90 <col:8> 'int' lvalue Var 0x3bb16f8 'i' 'int' 568 // | | `-IntegerLiteral 0x3bb1ce0 <col:10> 'int' 0 569 // | |-CompoundStmt 0x3bb1d88 <col:13, line:17:3> 570 // | | `-BreakStmt 0x3bb1d80 <line:16:4> 571 // | `-<<<NULL>>> 572 func transpileDoStmt(n *ast.DoStmt, p *program.Program) ( 573 goast.Stmt, []goast.Stmt, []goast.Stmt, error) { 574 var forOperator ast.ForStmt 575 forOperator.AddChild(nil) 576 forOperator.AddChild(nil) 577 forOperator.AddChild(nil) 578 forOperator.AddChild(nil) 579 c := &ast.CompoundStmt{} 580 if n.Children()[0] != nil { 581 if comp, ok := n.Children()[0].(*ast.CompoundStmt); ok { 582 c = comp 583 } else { 584 c.AddChild(n.Children()[0]) 585 } 586 } 587 if n.Children()[1] != nil { 588 ifBreak := createIfWithNotConditionAndBreak(n.Children()[1]) 589 c.AddChild(&ifBreak) 590 } 591 forOperator.AddChild(c) 592 return transpileForStmt(&forOperator, p) 593 } 594 595 // createIfWithNotConditionAndBreak - create operator IF like on next example 596 // of C code: 597 // 598 // if ( !(condition) ) { 599 // break; 600 // } 601 // 602 // Example of AST tree: 603 // 604 // `-IfStmt 0x3bb1da8 <line:15:3, line:17:3> 605 // |-<<<NULL>>> 606 // |-UnaryOperator 0x3bb1d60 <line:15:6, col:11> 'int' prefix '!' 607 // | `-ParenExpr 0x3bb1d40 <col:7, col:11> 'int' 608 // | `- CONDITION 609 // |-CompoundStmt 0x3bb1d88 <col:13, line:17:3> 610 // | `-BreakStmt 0x3bb1d80 <line:16:4> 611 // `-<<<NULL>>> 612 func createIfWithNotConditionAndBreak(condition ast.Node) (ifStmt ast.IfStmt) { 613 ifStmt.AddChild(nil) 614 615 var par ast.ParenExpr 616 var unitary ast.UnaryOperator 617 618 if typ, ok := ast.GetTypeIfExist(condition); ok { 619 par.Type = *typ 620 unitary.Type = *typ 621 } else { 622 panic(fmt.Errorf("type %T is not implemented in createIfWithNotConditionAndBreak", condition)) 623 } 624 625 par.AddChild(condition) 626 unitary.Operator = "!" 627 unitary.AddChild(&par) 628 629 ifStmt.AddChild(&unitary) 630 631 var c ast.CompoundStmt 632 c.AddChild(&ast.BreakStmt{}) 633 ifStmt.AddChild(&c) 634 ifStmt.AddChild(nil) 635 636 return 637 } 638 639 func transpileContinueStmt(n *ast.ContinueStmt, p *program.Program) (*goast.BranchStmt, error) { 640 return &goast.BranchStmt{ 641 Tok: token.CONTINUE, 642 }, nil 643 }