diff --git a/transpiler/binary.go b/transpiler/binary.go index 4d31b5632..2c9b8f80a 100644 --- a/transpiler/binary.go +++ b/transpiler/binary.go @@ -37,7 +37,7 @@ func transpileBinaryOperatorComma(n *ast.BinaryOperator, p *program.Program) ( return right[0], preStmts, nil } -func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) ( +func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsStmt bool) ( goast.Expr, string, []goast.Stmt, []goast.Stmt, error) { preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} @@ -95,7 +95,10 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) ( bComma.Type = c.Type bComma.AddChild(c) bComma.AddChild(&bSecond) - return transpileBinaryOperator(&bComma, p) + + // exprIsStmt now changes to false to stop any AST children from + // not being safely wrapped in a closure. + return transpileBinaryOperator(&bComma, p, false) } } } @@ -124,14 +127,14 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) ( // | `-ImplicitCastExpr 0x21a7898 'int' // | `-DeclRefExpr 0x21a7870 'int' lvalue Var 0x21a7748 'y' 'int' if getTokenForOperator(n.Operator) == token.COMMA { - stmts, st, newPre, newPost, err := transpileToExpr(n.Children[0], p) + stmts, st, newPre, newPost, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, "unknown50", nil, nil, err } preStmts = append(preStmts, newPre...) preStmts = append(preStmts, util.NewExprStmt(stmts)) postStmts = append(postStmts, newPost...) - stmts, st, newPre, newPost, err = transpileToExpr(n.Children[1], p) + stmts, st, newPre, newPost, err = transpileToExpr(n.Children[1], p, false) if err != nil { return nil, "unknown51", nil, nil, err } @@ -140,14 +143,14 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) ( return stmts, st, preStmts, postStmts, nil } - left, leftType, newPre, newPost, err := transpileToExpr(n.Children[0], p) + left, leftType, newPre, newPost, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, "unknown52", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) - right, rightType, newPre, newPost, err := transpileToExpr(n.Children[1], p) + right, rightType, newPre, newPost, err := transpileToExpr(n.Children[1], p, false) if err != nil { return nil, "unknown53", nil, nil, err } @@ -174,8 +177,9 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) ( p.AddMessage(ast.GenerateWarningMessage(err, n)) } - return util.NewBinaryExpr(left, operator, right, resolvedLeftType), "bool", - preStmts, postStmts, nil + expr := util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt) + + return expr, "bool", preStmts, postStmts, nil } // The right hand argument of the shift left or shift right operators @@ -189,8 +193,8 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) ( right = util.NewNil() } - return util.NewBinaryExpr(left, operator, right, "uint64"), leftType, - preStmts, postStmts, nil + return util.NewBinaryExpr(left, operator, right, "uint64", exprIsStmt), + leftType, preStmts, postStmts, nil } if operator == token.NEQ || operator == token.EQL { @@ -212,7 +216,7 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) ( allocSize := GetAllocationSizeNode(n.Children[1]) if allocSize != nil { - allocSizeExpr, _, newPre, newPost, err := transpileToExpr(allocSize, p) + allocSizeExpr, _, newPre, newPost, err := transpileToExpr(allocSize, p, false) preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) if err != nil { @@ -237,7 +241,7 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) ( right = util.NewCallExpr( "make", util.NewTypeIdent(toType), - util.NewBinaryExpr(allocSizeExpr, token.QUO, util.NewIntLit(elementSize), "int"), + util.NewBinaryExpr(allocSizeExpr, token.QUO, util.NewIntLit(elementSize), "int", false), ) } else { right, err = types.CastExpr(p, right, rightType, returnType) @@ -292,7 +296,7 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) ( p.AddMessage(ast.GenerateWarningMessage(err, n)) } - return util.NewBinaryExpr(left, operator, right, resolvedLeftType), + return util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt), types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType), preStmts, postStmts, nil } diff --git a/transpiler/branch.go b/transpiler/branch.go index 71bc2dfa5..5770a22a3 100644 --- a/transpiler/branch.go +++ b/transpiler/branch.go @@ -60,7 +60,7 @@ func transpileIfStmt(n *ast.IfStmt, p *program.Program) ( panic("non-nil child 0 in IfStmt") } - conditional, conditionalType, newPre, newPost, err := transpileToExpr(children[1], p) + conditional, conditionalType, newPre, newPost, err := transpileToExpr(children[1], p, false) if err != nil { return nil, nil, nil, err } @@ -247,7 +247,7 @@ func transpileForStmt(n *ast.ForStmt, p *program.Program) ( if children[2] != nil { var conditionType string var newPre, newPost []goast.Stmt - condition, conditionType, newPre, newPost, err = transpileToExpr(children[2], p) + condition, conditionType, newPre, newPost, err = transpileToExpr(children[2], p, false) if err != nil { return nil, nil, nil, err } diff --git a/transpiler/call.go b/transpiler/call.go index ceaf9c908..87b83d9bf 100644 --- a/transpiler/call.go +++ b/transpiler/call.go @@ -104,7 +104,7 @@ func transpileCallExpr(n *ast.CallExpr, p *program.Program) ( argTypes := []string{} i := 0 for _, arg := range n.Children[1:] { - e, eType, newPre, newPost, err := transpileToExpr(arg, p) + e, eType, newPre, newPost, err := transpileToExpr(arg, p, false) if err != nil { return nil, "unknown2", nil, nil, err } diff --git a/transpiler/declarations.go b/transpiler/declarations.go index 1a6134471..b0c15197a 100644 --- a/transpiler/declarations.go +++ b/transpiler/declarations.go @@ -232,6 +232,7 @@ func transpileVarDecl(p *program.Program, n *ast.VarDecl) ( util.NewTypeIdent("os."+util.Ucfirst(name[2:len(name)-1])), ), "*noarch.File", + true, ), ) @@ -248,6 +249,7 @@ func transpileVarDecl(p *program.Program, n *ast.VarDecl) ( util.NewTypeIdent("os."+util.Ucfirst(name)), ), theType, + true, ), ) diff --git a/transpiler/enum.go b/transpiler/enum.go index c17922559..d2c241e58 100644 --- a/transpiler/enum.go +++ b/transpiler/enum.go @@ -28,11 +28,13 @@ func ctypeEnumValue(value int, t token.Token) goast.Expr { token.SHL, util.NewIntLit(value), "int", + false, ), }, t, util.NewIntLit(8), "int", + false, ), } } @@ -86,7 +88,7 @@ func transpileEnumConstantDecl(p *program.Program, n *ast.EnumConstantDecl) ( default: if len(n.Children) > 0 { var err error - value, _, preStmts, postStmts, err = transpileToExpr(n.Children[0], p) + value, _, preStmts, postStmts, err = transpileToExpr(n.Children[0], p, false) if err != nil { panic(err) } diff --git a/transpiler/functions.go b/transpiler/functions.go index 4fe441a19..01223bf0b 100644 --- a/transpiler/functions.go +++ b/transpiler/functions.go @@ -224,7 +224,7 @@ func transpileReturnStmt(n *ast.ReturnStmt, p *program.Program) ( return &goast.ReturnStmt{}, nil, nil, nil } - e, eType, preStmts, postStmts, err := transpileToExpr(n.Children[0], p) + e, eType, preStmts, postStmts, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, nil, nil, err } diff --git a/transpiler/operators.go b/transpiler/operators.go index 4e971d7b8..e4ff0ed92 100644 --- a/transpiler/operators.go +++ b/transpiler/operators.go @@ -33,21 +33,21 @@ func transpileConditionalOperator(n *ast.ConditionalOperator, p *program.Program preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} - a, aType, newPre, newPost, err := transpileToExpr(n.Children[0], p) + a, aType, newPre, newPost, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, "", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) - b, bType, newPre, newPost, err := transpileToExpr(n.Children[1], p) + b, bType, newPre, newPost, err := transpileToExpr(n.Children[1], p, false) if err != nil { return nil, "", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) - c, cType, newPre, newPost, err := transpileToExpr(n.Children[2], p) + c, cType, newPre, newPost, err := transpileToExpr(n.Children[2], p, false) if err != nil { return nil, "", nil, nil, err } @@ -104,7 +104,7 @@ func transpileParenExpr(n *ast.ParenExpr, p *program.Program) ( preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} - e, eType, newPre, newPost, err := transpileToExpr(n.Children[0], p) + e, eType, newPre, newPost, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, "", nil, nil, err } @@ -121,13 +121,13 @@ func transpileParenExpr(n *ast.ParenExpr, p *program.Program) ( return r, eType, preStmts, postStmts, nil } -func transpileCompoundAssignOperator(n *ast.CompoundAssignOperator, p *program.Program) ( +func transpileCompoundAssignOperator(n *ast.CompoundAssignOperator, p *program.Program, exprIsStmt bool) ( goast.Expr, string, []goast.Stmt, []goast.Stmt, error) { operator := getTokenForOperator(n.Opcode) preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} - right, rightType, newPre, newPost, err := transpileToExpr(n.Children[1], p) + right, rightType, newPre, newPost, err := transpileToExpr(n.Children[1], p, false) if err != nil { return nil, "", nil, nil, err } @@ -159,7 +159,7 @@ func transpileCompoundAssignOperator(n *ast.CompoundAssignOperator, p *program.P argLHS := util.NewCallExpr(getterName) argOp := getTokenForOperator(binaryOperation) argRHS := right - argValue := util.NewBinaryExpr(argLHS, argOp, argRHS, "interface{}") + argValue := util.NewBinaryExpr(argLHS, argOp, argRHS, "interface{}", exprIsStmt) // Make Go expression resExpr := util.NewCallExpr(setterName, argValue) @@ -169,7 +169,7 @@ func transpileCompoundAssignOperator(n *ast.CompoundAssignOperator, p *program.P } } - left, leftType, newPre, newPost, err := transpileToExpr(n.Children[0], p) + left, leftType, newPre, newPost, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, "", nil, nil, err } @@ -193,7 +193,7 @@ func transpileCompoundAssignOperator(n *ast.CompoundAssignOperator, p *program.P p.AddMessage(ast.GenerateWarningMessage(err, n)) } - return util.NewBinaryExpr(left, operator, right, resolvedLeftType), + return util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt), "", preStmts, postStmts, nil } diff --git a/transpiler/switch.go b/transpiler/switch.go index 640930d5d..92badc716 100644 --- a/transpiler/switch.go +++ b/transpiler/switch.go @@ -29,7 +29,7 @@ func transpileSwitchStmt(n *ast.SwitchStmt, p *program.Program) ( // The condition is the expression to be evaulated against each of the // cases. - condition, _, newPre, newPost, err := transpileToExpr(n.Children[len(n.Children)-2], p) + condition, _, newPre, newPost, err := transpileToExpr(n.Children[len(n.Children)-2], p, false) if err != nil { return nil, nil, nil, err } @@ -193,7 +193,7 @@ func transpileCaseStmt(n *ast.CaseStmt, p *program.Program) ( preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} - c, _, newPre, newPost, err := transpileToExpr(n.Children[0], p) + c, _, newPre, newPost, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, nil, nil, err } diff --git a/transpiler/transpiler.go b/transpiler/transpiler.go index c25e05666..00aa97aff 100644 --- a/transpiler/transpiler.go +++ b/transpiler/transpiler.go @@ -59,7 +59,7 @@ func TranspileAST(fileName, packageName string, p *program.Program, root ast.Nod return err } -func transpileToExpr(node ast.Node, p *program.Program) ( +func transpileToExpr(node ast.Node, p *program.Program, exprIsStmt bool) ( expr goast.Expr, exprType string, preStmts []goast.Stmt, @@ -88,7 +88,7 @@ func transpileToExpr(node ast.Node, p *program.Program) ( expr, exprType, preStmts, postStmts, err = transpileArraySubscriptExpr(n, p) case *ast.BinaryOperator: - expr, exprType, preStmts, postStmts, err = transpileBinaryOperator(n, p) + expr, exprType, preStmts, postStmts, err = transpileBinaryOperator(n, p, exprIsStmt) case *ast.UnaryOperator: expr, exprType, preStmts, postStmts, err = transpileUnaryOperator(n, p) @@ -97,7 +97,7 @@ func transpileToExpr(node ast.Node, p *program.Program) ( expr, exprType, preStmts, postStmts, err = transpileMemberExpr(n, p) case *ast.ImplicitCastExpr: - expr, exprType, preStmts, postStmts, err = transpileToExpr(n.Children[0], p) + expr, exprType, preStmts, postStmts, err = transpileToExpr(n.Children[0], p, false) case *ast.DeclRefExpr: expr, exprType, err = transpileDeclRefExpr(n, p) @@ -109,7 +109,7 @@ func transpileToExpr(node ast.Node, p *program.Program) ( expr, exprType, preStmts, postStmts, err = transpileParenExpr(n, p) case *ast.CStyleCastExpr: - expr, exprType, preStmts, postStmts, err = transpileToExpr(n.Children[0], p) + expr, exprType, preStmts, postStmts, err = transpileToExpr(n.Children[0], p, false) case *ast.CharacterLiteral: expr, exprType, err = transpileCharacterLiteral(n), "char", nil @@ -118,7 +118,7 @@ func transpileToExpr(node ast.Node, p *program.Program) ( expr, exprType, preStmts, postStmts, err = transpileCallExpr(n, p) case *ast.CompoundAssignOperator: - return transpileCompoundAssignOperator(n, p) + return transpileCompoundAssignOperator(n, p, exprIsStmt) case *ast.UnaryExprOrTypeTraitExpr: return transpileUnaryExprOrTypeTraitExpr(n, p) @@ -209,7 +209,7 @@ func transpileToStmt(node ast.Node, p *program.Program) ( } // We do not care about the return type. - expr, _, preStmts, postStmts, err = transpileToExpr(node, p) + expr, _, preStmts, postStmts, err = transpileToExpr(node, p, false) if err != nil { return } diff --git a/transpiler/unary.go b/transpiler/unary.go index a162a2c33..26890ca35 100644 --- a/transpiler/unary.go +++ b/transpiler/unary.go @@ -51,7 +51,7 @@ func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, argLHS := util.NewCallExpr(getterName) argOp := binaryOperator argRHS := util.NewIntLit(1) - argValue := util.NewBinaryExpr(argLHS, argOp, argRHS, "interface{}") + argValue := util.NewBinaryExpr(argLHS, argOp, argRHS, "interface{}", false) // Make Go expression resExpr := util.NewCallExpr(setterName, argValue) @@ -76,12 +76,12 @@ func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, Children: []ast.Node{}, }, }, - }, p) + }, p, false) } func transpileUnaryOperatorNot(n *ast.UnaryOperator, p *program.Program) ( goast.Expr, string, []goast.Stmt, []goast.Stmt, error) { - e, eType, preStmts, postStmts, err := transpileToExpr(n.Children[0], p) + e, eType, preStmts, postStmts, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, "", nil, nil, err } @@ -114,7 +114,7 @@ func transpileUnaryOperatorNot(n *ast.UnaryOperator, p *program.Program) ( // Dereferencing. func transpileUnaryOperatorMul(n *ast.UnaryOperator, p *program.Program) ( goast.Expr, string, []goast.Stmt, []goast.Stmt, error) { - e, eType, preStmts, postStmts, err := transpileToExpr(n.Children[0], p) + e, eType, preStmts, postStmts, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, "", nil, nil, err } @@ -163,7 +163,7 @@ func transpileUnaryOperator(n *ast.UnaryOperator, p *program.Program) ( } // Otherwise handle like a unary operator. - e, eType, newPre, newPost, err := transpileToExpr(n.Children[0], p) + e, eType, newPre, newPost, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, "", nil, nil, err } diff --git a/transpiler/variables.go b/transpiler/variables.go index 250e00cb3..04e25f628 100644 --- a/transpiler/variables.go +++ b/transpiler/variables.go @@ -31,7 +31,7 @@ func getDefaultValueForVar(p *program.Program, a *ast.VarDecl) ( return nil, "", nil, nil, nil } - defaultValue, defaultValueType, newPre, newPost, err := transpileToExpr(a.Children[0], p) + defaultValue, defaultValueType, newPre, newPost, err := transpileToExpr(a.Children[0], p, false) if err != nil { return nil, defaultValueType, newPre, newPost, err } @@ -135,14 +135,14 @@ func transpileArraySubscriptExpr(n *ast.ArraySubscriptExpr, p *program.Program) postStmts := []goast.Stmt{} children := n.Children - expression, expressionType, newPre, newPost, err := transpileToExpr(children[0], p) + expression, expressionType, newPre, newPost, err := transpileToExpr(children[0], p, false) if err != nil { return nil, "", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) - index, _, newPre, newPost, err := transpileToExpr(children[1], p) + index, _, newPre, newPost, err := transpileToExpr(children[1], p, false) if err != nil { return nil, "", nil, nil, err } @@ -168,7 +168,7 @@ func transpileMemberExpr(n *ast.MemberExpr, p *program.Program) ( preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} - lhs, lhsType, newPre, newPost, err := transpileToExpr(n.Children[0], p) + lhs, lhsType, newPre, newPost, err := transpileToExpr(n.Children[0], p, false) if err != nil { return nil, "", nil, nil, err } diff --git a/types/cast.go b/types/cast.go index f848a094f..2821c3ab8 100644 --- a/types/cast.go +++ b/types/cast.go @@ -125,7 +125,15 @@ func CastExpr(p *program.Program, expr ast.Expr, fromType, toType string) (ast.E } for _, v := range types { if fromType == v && toType == "bool" { - return util.NewBinaryExpr(expr, token.NEQ, util.NewIntLit(0), toType), nil + e := util.NewBinaryExpr( + expr, + token.NEQ, + util.NewIntLit(0), + toType, + false, + ) + + return e, nil } } @@ -191,7 +199,9 @@ func CastExpr(p *program.Program, expr ast.Expr, fromType, toType string) (ast.E // Anything that is a pointer can be compared to nil if fromType[0] == '*' && toType == "bool" { - return util.NewBinaryExpr(expr, token.NEQ, util.NewNil(), toType), nil + e := util.NewBinaryExpr(expr, token.NEQ, util.NewNil(), toType, false) + + return e, nil } if fromType == "[]byte" && toType == "bool" { diff --git a/types/cast_test.go b/types/cast_test.go index 6c36ac1ba..f4083f42b 100644 --- a/types/cast_test.go +++ b/types/cast_test.go @@ -40,7 +40,7 @@ func TestCast(t *testing.T) { {args{util.NewIntLit(1), "int", "__uint16_t"}, util.NewCallExpr("uint16", util.NewIntLit(1))}, // Casting to bool - {args{util.NewIntLit(1), "int", "bool"}, util.NewBinaryExpr(util.NewIntLit(1), token.NEQ, util.NewIntLit(0), "bool")}, + {args{util.NewIntLit(1), "int", "bool"}, util.NewBinaryExpr(util.NewIntLit(1), token.NEQ, util.NewIntLit(0), "bool", false)}, // Casting from bool. This is a special case becuase C int and bool // values are very commonly used interchangably. diff --git a/util/goast.go b/util/goast.go index 813915608..8f9df3e64 100644 --- a/util/goast.go +++ b/util/goast.go @@ -160,7 +160,27 @@ func NewFuncClosure(returnType string, stmts ...goast.Stmt) *goast.CallExpr { // You should use this instead of BinaryExpr directly so that nil left and right // operands can be caught (and panic) before Go tried to render the source - // which would result in a very hard to debug error. -func NewBinaryExpr(left goast.Expr, operator token.Token, right goast.Expr, returnType string) goast.Expr { +// +// Assignment operators in C can be nested inside other expressions, like: +// +// a + (b += 3) +// +// In Go this is not allowed. Since the operators mutate variables it is not +// possible in some cases to move the statements before or after. The only safe +// (and generic) way around this is to create an immediately executing closure, +// like: +// +// a + (func () int { b += 3; return b }()) +// +// In a lot of cases this may be unnecessary and obfuscate the Go output but +// these will have to be optimised over time and be strict about the +// situation they are simplifying. +// +// If stmt is true then the binary expression is the whole statement. This means +// that the closure above does not need to applied. This makes the output code +// much neater. +func NewBinaryExpr(left goast.Expr, operator token.Token, right goast.Expr, + returnType string, stmt bool) goast.Expr { PanicIfNil(left, "left is nil") PanicIfNil(right, "right is nil") @@ -170,36 +190,27 @@ func NewBinaryExpr(left goast.Expr, operator token.Token, right goast.Expr, retu Y: right, } - // Assignment operators in C can be nested inside other expressions, like: - // - // a + (b += 3) - // - // In Go this is not allowed. Since the operators mutate variables it is not - // possible in some cases to move the statements before or after. The only - // safe way around this is to create an immediately executing closure, like: - // - // a + (func () int { b += 3; return b }()) - // - // In a lot of cases this may be unnecessary and obfuscate the Go output but - // these will have to be optimised over time and be strict about the - // situation they are simplifying. - switch operator { - case token.ASSIGN, - token.ADD_ASSIGN, - token.SUB_ASSIGN, - token.MUL_ASSIGN, - token.QUO_ASSIGN, - token.REM_ASSIGN, - token.AND_ASSIGN, - token.OR_ASSIGN, - token.XOR_ASSIGN, - token.SHL_ASSIGN, - token.SHR_ASSIGN, - token.AND_NOT_ASSIGN: - returnStmt := &goast.ReturnStmt{ - Results: []goast.Expr{left}, + // Wrap the assignment operator in a closure if we must. + if !stmt { + switch operator { + case token.ASSIGN, + token.ADD_ASSIGN, + token.SUB_ASSIGN, + token.MUL_ASSIGN, + token.QUO_ASSIGN, + token.REM_ASSIGN, + token.AND_ASSIGN, + token.OR_ASSIGN, + token.XOR_ASSIGN, + token.SHL_ASSIGN, + token.SHR_ASSIGN, + token.AND_NOT_ASSIGN: + returnStmt := &goast.ReturnStmt{ + Results: []goast.Expr{left}, + } + + b = NewFuncClosure(returnType, NewExprStmt(b), returnStmt) } - b = NewFuncClosure(returnType, NewExprStmt(b), returnStmt) } return b