/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.ir.transform.expression;
import gw.internal.gosu.ir.nodes.IRMethod;
import gw.internal.gosu.ir.transform.AbstractElementTransformer;
import gw.internal.gosu.ir.transform.ExpressionTransformer;
import gw.internal.gosu.ir.transform.TopLevelTransformationContext;
import gw.internal.gosu.parser.ParameterizedGosuConstructorInfo;
import gw.internal.gosu.parser.TypeLord;
import gw.lang.ir.IRExpression;
import gw.lang.ir.IRType;
import gw.lang.parser.IExpression;
import gw.lang.reflect.IConstructorInfo;
import gw.lang.reflect.IPlaceholder;
import gw.lang.reflect.IType;
import gw.lang.reflect.gs.IGosuConstructorInfo;
import gw.lang.reflect.java.IJavaConstructorInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
*/
public abstract class AbstractExpressionTransformer<T extends IExpression> extends AbstractElementTransformer<T>
{
public AbstractExpressionTransformer( TopLevelTransformationContext cc, T parsedElem )
{
super( cc, parsedElem );
}
public final IRExpression compile()
{
IRExpression expr = compile_impl();
//## todo: see about re-enabling line numbers at expressions *after* we can filter out all the crap that screws up stepping in the debugger
// if( _expr() instanceof IHasOperatorLineNumber )
// {
// expr.setLineNumber( ((IHasOperatorLineNumber)_expr()).getOperatorLineNumber() );
// }
// else
// {
// expr.setLineNumber( _expr().getLineNum() );
// }
return expr;
}
protected abstract IRExpression compile_impl();
public T _expr()
{
return getParsedElement();
}
static List<IRType> getIRParameters( IConstructorInfo ci )
{
if( ci.getParameters().length == 0 )
{
return Collections.emptyList();
}
if( ci instanceof IJavaConstructorInfo)
{
Class<?>[] parameterClasses = ((IJavaConstructorInfo) ci).getRawConstructor().getParameterTypes();
List<IRType> irTypes = new ArrayList<IRType>( parameterClasses.length );
for (Class parameterClass : parameterClasses) {
irTypes.add( getDescriptor( parameterClass ) );
}
return irTypes;
}
else if( ci instanceof IGosuConstructorInfo)
{
IGosuConstructorInfo cInfo = (IGosuConstructorInfo) ci;
while( cInfo instanceof ParameterizedGosuConstructorInfo)
{
ParameterizedGosuConstructorInfo pdfs = (ParameterizedGosuConstructorInfo)cInfo;
cInfo = pdfs.getBackingConstructorInfo();
}
List<IRType> boundedTypes = new ArrayList<IRType>(cInfo.getArgs().size());
for( int i = 0; i < cInfo.getArgs().size(); i++ )
{
IType type = cInfo.getArgs().get(i).getType();
boundedTypes.add( getDescriptor( TypeLord.getDefaultParameterizedTypeWithTypeVars( type ) ) );
}
return boundedTypes;
}
else
{
List<IRType> boundedTypes = new ArrayList<IRType>( ci.getParameters().length );
for( IType type : getTypes( ci.getParameters() ) )
{
boundedTypes.add( getDescriptor( type ) );
}
return boundedTypes;
}
}
protected IRExpression shortCircuitValue( IRType expressionType )
{
if( _expr().getType().isPrimitive() )
{
return getDefaultConstIns( _expr().getType() );
}
else
{
return buildCast( expressionType, nullLiteral() );
}
}
protected void pushArgumentsNoCasting( IRMethod irMethod, IExpression[] args, List<IRExpression> irArgs )
{
_pushArguments( irMethod, args, irArgs, false );
}
protected void pushArgumentsWithCasting( IRMethod irMethod, IExpression[] args, List<IRExpression> irArgs )
{
_pushArguments( irMethod, args, irArgs, true );
}
private void _pushArguments( IRMethod irMethod, IExpression[] args, List<IRExpression> irArgs, boolean bCast )
{
if( args != null )
{
List<IRType> paramClasses = bCast ? irMethod.getExplicitParameterTypes() : Collections.<IRType>emptyList();
for( int i = 0; i < args.length; i++ )
{
IExpression arg = args[i];
IRExpression irArg = ExpressionTransformer.compile( arg, _cc() );
if( bCast )
{
IRType type = paramClasses.get( i );
if( type.isPrimitive() && arg.getType() instanceof IPlaceholder && ((IPlaceholder)arg.getType()).isPlaceholder() )
{
irArg = unboxValueToType( type, irArg );
}
else
{
irArg = maybeCast( paramClasses, i, irArg );
}
}
irArgs.add( irArg );
}
}
}
private IRExpression maybeCast( List<IRType> paramClasses, int i, IRExpression irArg ) {
// Maybe cast if not directly assignable (e.g., cross cast)
IRType paramClass = paramClasses.get( i );
if( !paramClass.isAssignableFrom( irArg.getType() ) )
{
irArg = buildCast( paramClass, irArg );
}
return irArg;
}
}