/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.ir.transform.statement; import gw.internal.gosu.parser.statements.ReturnStatement; import gw.internal.gosu.ir.transform.ExpressionTransformer; import gw.internal.gosu.ir.transform.TopLevelTransformationContext; import gw.lang.ir.IRStatement; import gw.lang.ir.IRExpression; import gw.lang.ir.IRType; import gw.lang.ir.expression.IRNullLiteral; import gw.lang.ir.expression.IRIdentifier; import gw.lang.ir.statement.IRReturnStatement; import gw.lang.ir.statement.IRStatementList; import gw.lang.ir.statement.IRSyntheticStatement; import gw.lang.ir.statement.IRAssignmentStatement; import gw.lang.reflect.IType; import gw.lang.reflect.java.IJavaType; import gw.lang.reflect.java.JavaTypes; import gw.lang.parser.IParsedElement; import gw.lang.parser.statements.IClassStatement; import gw.lang.parser.statements.ITryCatchFinallyStatement; import gw.lang.parser.expressions.IBlockLiteralExpression; import gw.lang.reflect.java.JavaTypes; /** */ public class ReturnStatementTransformer extends AbstractStatementTransformer<ReturnStatement> { public static IRStatement compile( TopLevelTransformationContext cc, ReturnStatement stmt ) { ReturnStatementTransformer gen = new ReturnStatementTransformer( cc, stmt ); return gen.compile(); } private ReturnStatementTransformer( TopLevelTransformationContext cc, ReturnStatement stmt ) { super( cc, stmt ); } @Override protected IRStatement compile_impl() { IType retType = _stmt().getValue().getType(); if( retType != JavaTypes.pVOID() ) { IRExpression returnValue = compileReturnExpr( retType ); return makeReturnStmt( returnValue ); } else if( _cc().isBlockInvoke() ) { // Blocks can return nothing but consist of a single expression that has a value. // If that's the case, we wrap that call in a synthetic statement so that the value gets popped off, // then follow it with the actual return statement that returns null. if( _stmt().getValue() != null ) { return new IRStatementList(false, new IRSyntheticStatement( compileReturnExpr( retType ) ), makeReturnStmt( nullLiteral() ) ); } else { return makeReturnStmt( nullLiteral() ); } } else { return buildReturn( ); } } private IRReturnStatement makeReturnStmt( IRExpression returnValue ) { if( needsTempVar() ) { IRAssignmentStatement tempVarAssignment = buildAssignment( _cc().makeAndIndexTempSymbol( returnValue.getType() ), returnValue ); IRIdentifier id = identifier( tempVarAssignment.getSymbol() ); return new IRReturnStatement( tempVarAssignment, id ); } else { return new IRReturnStatement( null, returnValue ); } } private boolean needsTempVar() { return finallyBlockInParentHierarchy( _stmt() ); } private boolean finallyBlockInParentHierarchy( IParsedElement stmt ) { if( stmt == null || stmt instanceof IBlockLiteralExpression || stmt instanceof IClassStatement ) { return false; } else if( stmt instanceof ITryCatchFinallyStatement && ((ITryCatchFinallyStatement) stmt).getFinallyStatement() != null) { return true; } else { return finallyBlockInParentHierarchy( stmt.getParent() ); } } private IRExpression compileReturnExpr( IType retType ) { // Compile the return value expression IRExpression expression = ExpressionTransformer.compile( _stmt().getValue(), _cc() ); // handle implicit boxing/unbocking in block invoke methods or if( (_cc().isBlockInvoke() || _cc().isFragmentEvaluation() ) && retType.isPrimitive() ) { expression = boxValue( retType, expression ); } // If we can determine what the return type of the enclosing function is, we're not within a block, and // we're not return null, and the return type isn't assignable from the actual type of the expression, // then we need to insert a cast. if (!_cc().isBlockInvoke() && _cc().getCurrentFunctionReturnType() != null) { IRType returnTypeDescriptor = getDescriptor( _cc().getCurrentFunctionReturnType() ); if ( (!(expression instanceof IRNullLiteral) || finallyBlockInParentHierarchy( _stmt() )) && !returnTypeDescriptor.isAssignableFrom( expression.getType() ) ) { expression = buildCast( returnTypeDescriptor, expression ); } } return expression; } }