func rewriteStmt(stmt *cc.Stmt) { // TODO: Double-check stmt.Labels switch stmt.Op { case cc.ARGBEGIN: panic(fmt.Sprintf("unexpected ARGBEGIN")) case cc.Do: // Rewrite do { ... } while(x) // to for(;;) { ... if(!x) break } // Since rewriteStmt is called in a preorder traversal, // the recursion into the children will clean up x // in the if condition as needed. stmt.Op = cc.For x := stmt.Expr stmt.Expr = nil stmt.Body = forceBlock(stmt.Body) stmt.Body.Block = append(stmt.Body.Block, &cc.Stmt{ Op: cc.If, Expr: &cc.Expr{Op: cc.Not, Left: x}, Body: &cc.Stmt{Op: cc.Break}, }) case cc.While: stmt.Op = cc.For fallthrough case cc.For: before1, _ := extractSideEffects(stmt.Pre, sideStmt|sideNoAfter) before2, _ := extractSideEffects(stmt.Expr, sideNoAfter) if len(before2) > 0 { x := stmt.Expr stmt.Expr = nil stmt.Body = forceBlock(stmt.Body) top := &cc.Stmt{ Op: cc.If, Expr: &cc.Expr{Op: cc.Not, Left: x}, Body: &cc.Stmt{Op: cc.Break}, } stmt.Body.Block = append(append(before2, top), stmt.Body.Block...) } if len(before1) > 0 { old := copyStmt(stmt) stmt.Pre = nil stmt.Expr = nil stmt.Post = nil stmt.Body = nil stmt.Op = c2go.BlockNoBrace stmt.Block = append(before1, old) } before, after := extractSideEffects(stmt.Post, sideStmt) if len(before)+len(after) > 0 { all := append(append(before, &cc.Stmt{Op: cc.StmtExpr, Expr: stmt.Post}), after...) stmt.Post = &cc.Expr{Op: c2go.ExprBlock, Block: all} } case cc.If, cc.Return: before, _ := extractSideEffects(stmt.Expr, sideNoAfter) if len(before) > 0 { old := copyStmt(stmt) stmt.Expr = nil stmt.Body = nil stmt.Else = nil stmt.Op = c2go.BlockNoBrace stmt.Block = append(before, old) } case cc.StmtExpr: before, after := extractSideEffects(stmt.Expr, sideStmt) if len(before)+len(after) > 0 { old := copyStmt(stmt) stmt.Expr = nil stmt.Op = c2go.BlockNoBrace stmt.Block = append(append(before, old), after...) } case cc.Goto: // TODO: Figure out where the goto goes and maybe rewrite // to labeled break/continue. // Otherwise move code or something. case cc.Switch: // TODO: Change default fallthrough to default break. before, _ := extractSideEffects(stmt.Expr, sideNoAfter) rewriteSwitch(stmt) if len(before) > 0 { old := copyStmt(stmt) stmt.Expr = nil stmt.Body = nil stmt.Else = nil stmt.Op = c2go.BlockNoBrace stmt.Block = append(before, old) } } }