/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.ir.transform.statement;
import gw.lang.ir.IRExpression;
import gw.lang.ir.IRStatement;
import gw.lang.ir.IRType;
import gw.internal.gosu.ir.nodes.IRProperty;
import gw.internal.gosu.ir.nodes.IRPropertyFactory;
import gw.lang.ir.expression.IRNullLiteral;
import gw.internal.gosu.ir.transform.ExpressionTransformer;
import gw.internal.gosu.ir.transform.TopLevelTransformationContext;
import gw.internal.gosu.parser.CapturedSymbol;
import gw.internal.gosu.parser.DynamicPropertySymbol;
import gw.internal.gosu.parser.DynamicSymbol;
import gw.internal.gosu.parser.ScopedDynamicSymbol;
import gw.internal.gosu.parser.AbstractDynamicSymbol;
import gw.lang.parser.ISymbol;
import gw.lang.parser.statements.IAssignmentStatement;
import gw.lang.reflect.IType;
import gw.lang.reflect.gs.IExternalSymbolMap;
import java.util.Arrays;
/**
*/
public class AssignmentStatementTransformer extends AbstractStatementTransformer<IAssignmentStatement>
{
public static IRStatement compile( TopLevelTransformationContext cc, IAssignmentStatement stmt )
{
AssignmentStatementTransformer gen = new AssignmentStatementTransformer( cc, stmt );
return gen.compile();
}
private AssignmentStatementTransformer( TopLevelTransformationContext cc, IAssignmentStatement stmt )
{
super( cc, stmt );
}
@Override
protected IRStatement compile_impl()
{
ISymbol symbol = _stmt().getIdentifier().getSymbol();
IType type = symbol.getType();
if ( _cc().isExternalSymbol( symbol.getName() ) )
{
IRExpression setterCall = callMethod( IExternalSymbolMap.class, "setValue", new Class[]{String.class, Object.class},
pushExternalSymbolsMap(),
Arrays.asList( pushConstant( symbol.getName() ),
boxValue( _stmt().getExpression().getType(), ExpressionTransformer.compile( _stmt().getExpression(), _cc() ) ) ) );
return buildMethodCall( setterCall );
}
else if( symbol instanceof ScopedDynamicSymbol )
{
return setScopedSymbolValue( symbol, _stmt().getExpression() );
}
else if( symbol instanceof DynamicPropertySymbol )
{
// Lhs is a Property
final DynamicPropertySymbol dps = (DynamicPropertySymbol)symbol;
IRProperty irProperty = IRPropertyFactory.createIRProperty(dps);
IRExpression rhsValue = transformRHS( symbol );
IRExpression root= pushRoot(dps, irProperty);
return buildMethodCall( callMethod( irProperty.getSetterMethod(), root, exprList( rhsValue ) ) );
}
else
{
IRExpression rhsValue = transformRHS( symbol );
if( symbol instanceof DynamicSymbol )
{
// Lhs is a Field
DynamicSymbol field = (DynamicSymbol)symbol;
IRProperty irProperty = IRPropertyFactory.createIRProperty( symbol );
IRExpression root = pushRoot(field, irProperty);
return setField( irProperty, root, rhsValue );
}
else if( symbol instanceof CapturedSymbol )
{
// Captured symbol is stored as a Field on an anonymous inner class (one elem array of symbol's type)
// e.g., val$myFiield[0] = value
IRProperty irProp = IRPropertyFactory.createIRProperty( getGosuClass(), symbol );
return buildArrayStore( getField( irProp, pushThis() ),
numericLiteral(0), rhsValue, irProp.getType().getComponentType() );
}
else if( symbol.getIndex() >= 0 )
{
// Lhs is a local var
if( symbol.isValueBoxed() )
{
// Local var is captured in an anonymous inner class.
// Symbol's value maintained as a one elem array of symbol's type.
return buildArrayStore( identifier( _cc().getSymbol( symbol.getName() ) ),
numericLiteral( 0 ),
rhsValue,
getDescriptor( type ) );
}
else
{
// Simple local var
return buildAssignment( _cc().getSymbol( symbol.getName() ),
rhsValue );
}
} else {
throw new IllegalStateException("Found a symbol that we didn't know how to handle");
}
}
}
private IRExpression pushRoot(AbstractDynamicSymbol dps, IRProperty irProperty) {
IRExpression root;
if ( irProperty.isStatic() ) {
root = null;
} else if ( isMemberOnEnclosingType( dps ) != null ) {
root = pushOuter( dps.getGosuClass() );
} else {
root = pushThis();
}
return root;
}
private IRExpression transformRHS(ISymbol symbol) {
IRExpression rhsValue = ExpressionTransformer.compile( _stmt().getExpression(), _cc() );
IRType symbolType = getDescriptor(symbol.getType());
if (!(rhsValue instanceof IRNullLiteral) && !symbolType.isAssignableFrom(rhsValue.getType())) {
rhsValue = buildCast( symbolType, rhsValue );
}
return rhsValue;
}
}