/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.ir.transform.expression;
import gw.internal.gosu.ir.transform.ExpressionTransformer;
import gw.internal.gosu.ir.transform.TopLevelTransformationContext;
import gw.internal.gosu.parser.IGosuClassInternal;
import gw.internal.gosu.parser.TypeLord;
import gw.internal.gosu.parser.expressions.TypeIsExpression;
import gw.lang.ir.IRExpression;
import gw.lang.ir.IRSymbol;
import gw.lang.ir.expression.IRInstanceOfExpression;
import gw.lang.reflect.IType;
import gw.lang.reflect.TypeSystem;
import gw.lang.reflect.java.IJavaType;
/**
*/
public class TypeIsTransformer extends AbstractExpressionTransformer<TypeIsExpression>
{
public static IRExpression compile( TopLevelTransformationContext cc, TypeIsExpression expr )
{
TypeIsTransformer gen = new TypeIsTransformer( cc, expr );
return gen.compile();
}
private TypeIsTransformer( TopLevelTransformationContext cc, TypeIsExpression expr )
{
super( cc, expr );
}
protected IRExpression compile_impl()
{
IType lhsType = _expr().getLHS().getType();
IType rhsType = _expr().getRHS().evaluate();
if( lhsType.isPrimitive() || rhsType.isPrimitive() )
{
throw new IllegalStateException( "Primitive types not supported in typeis expression" );
}
if( (!rhsType.isParameterizedType() ||
rhsType == TypeLord.getDefaultParameterizedType( rhsType )) &&
(rhsType instanceof IGosuClassInternal ||
rhsType instanceof IJavaType) &&
(lhsType instanceof IGosuClassInternal ||
lhsType instanceof IJavaType) )
{
// Perf: use the INSTANCEOF bytecode when we are dealing with Java-based types that are not parameterized
// Note Gosu array types don't retain type info at runtime, so those can use instanceof regardless
IRExpression lhs = ExpressionTransformer.compile( _expr().getLHS(), _cc() );
return new IRInstanceOfExpression( lhs, getDescriptor( TypeLord.getPureGenericType( rhsType ) ) );
}
// We want to short-circuit to false if the lhs evaluates to null, so we generate code that looks like the following:
// temp = lhs
// return (temp == null ? false : rhs.isAssignableFrom(TypeSystem.getFromObject(temp)).booleanValue())
IRExpression lhs = ExpressionTransformer.compile( _expr().getLHS(), _cc() );
IRSymbol temp = _cc().makeAndIndexTempSymbol( lhs.getType() );
IRExpression getTypeCall = callStaticMethod( TypeSystem.class, "getFromObject", new Class[]{Object.class},
exprList( identifier( temp ) ) );
IRExpression isAssignableCall = callMethod( IType.class, "isAssignableFrom", new Class[]{IType.class},
ExpressionTransformer.compile( _expr().getRHS(), _cc() ),
exprList( getTypeCall ) );
return buildComposite(
buildAssignment( temp, lhs ),
buildNullCheckTernary(
identifier( temp ),
booleanLiteral( false ),
isAssignableCall ) );
}
}