/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.ir.transform.statement;
import gw.internal.gosu.parser.statements.ThrowStatement;
import gw.internal.gosu.parser.TypeLord;
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.IRSymbol;
import gw.lang.ir.expression.IRInstanceOfExpression;
import gw.lang.ir.statement.IRStatementList;
import gw.lang.parser.EvaluationException;
import gw.lang.reflect.java.IJavaType;
import gw.lang.reflect.java.JavaTypes;
import gw.lang.reflect.java.JavaTypes;
/**
*/
public class ThrowStatementTransformer extends AbstractStatementTransformer<ThrowStatement>
{
public static IRStatement compile( TopLevelTransformationContext cc, ThrowStatement stmt )
{
ThrowStatementTransformer compiler = new ThrowStatementTransformer( cc, stmt );
return compiler.compile();
}
private ThrowStatementTransformer( TopLevelTransformationContext cc, ThrowStatement stmt )
{
super( cc, stmt );
}
@Override
protected IRStatement compile_impl()
{
// The throw statement can throw any object. If we can statically determine that the RHS expression
// is definitely a throwable, then we can just do a throw. Otherwise, we need to do an if statement
// to check if it's a throwable; if so we cast it to Throwable and throw it, and if not we wrap it
// in an EvaluationException
IRExpression exceptionValue = ExpressionTransformer.compile( _stmt().getExpression(), _cc() );
if (TypeLord.isSubtype( _stmt().getExpression().getType(), JavaTypes.THROWABLE() ) ) {
// It's definitely a Throwable: if it's a synthetic type like a SOAP exception type, the verifier
// might not actually know it's a throwable, though
if ( !getDescriptor(Throwable.class).isAssignableFrom(exceptionValue.getType())) {
// If the IR type of the value isn't assignable to Throwable, then wrap it in a cast, since we know it will work
// out at runtime (unless someone constructed a totally invalid type loader, in which case . . . what can you do?)
exceptionValue = buildCast( getDescriptor(Throwable.class), exceptionValue );
}
return buildThrow( exceptionValue );
} else {
IRSymbol temp = _cc().makeAndIndexTempSymbol( getDescriptor( _stmt().getExpression().getType() ) );
IRStatement tempAssignment = buildAssignment( temp, exceptionValue );
IRExpression test = new IRInstanceOfExpression( identifier( temp ), getDescriptor( Throwable.class ) );
IRStatement trueCase = buildThrow( checkCast( Throwable.class, identifier( temp ) ) );
IRStatement falseCase = buildThrow( buildNewExpression( EvaluationException.class, new Class[]{String.class},
exprList( checkCast( String.class, identifier( temp ) ) ) ) );
IRStatement ifStatement = buildIfElse( test, trueCase, falseCase);
return new IRStatementList( false, tempAssignment, ifStatement);
}
}
}