/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.ir.transform.statement;
import gw.internal.gosu.ir.nodes.JavaClassIRType;
import gw.lang.ir.IRExpression;
import gw.lang.ir.IRStatement;
import gw.lang.ir.IRType;
import gw.lang.ir.expression.IRNullLiteral;
import gw.lang.ir.statement.IRAssignmentStatement;
import gw.lang.ir.statement.IRNoOpStatement;
import gw.internal.gosu.ir.transform.ExpressionTransformer;
import gw.internal.gosu.ir.transform.TopLevelTransformationContext;
import gw.internal.gosu.ir.transform.util.AccessibilityUtil;
import gw.internal.gosu.parser.DynamicSymbol;
import gw.internal.gosu.parser.ScopedDynamicSymbol;
import gw.internal.gosu.parser.Symbol;
import gw.lang.parser.GlobalScope;
import gw.lang.parser.IExpression;
import gw.lang.parser.expressions.IVarStatement;
import gw.lang.reflect.IType;
import java.util.Collections;
/**
*/
public class VarStatementTransformer extends AbstractStatementTransformer<IVarStatement>
{
public static IRStatement compile( TopLevelTransformationContext cc, IVarStatement stmt )
{
VarStatementTransformer compiler = new VarStatementTransformer( cc, stmt );
return compiler.compile();
}
private VarStatementTransformer( TopLevelTransformationContext cc, IVarStatement stmt )
{
super( cc, stmt );
}
@Override
protected IRStatement compile_impl()
{
IExpression asExp = _stmt().getAsExpression();
Symbol symbol = (Symbol)_stmt().getSymbol();
IType type = symbol.getType();
// Determine the initial value
IRExpression value = null;
if( asExp != null )
{
if( symbol instanceof ScopedDynamicSymbol )
{
//## todo: probably not support request/session vars anymore?
throw new UnsupportedOperationException( "Scoped vars not supported in Java classes files (for now)" );
}
else
{
value = ExpressionTransformer.compile( asExp, _cc() );
// If the value we're assigning isn't assignable to the symbol's type, we need to insert a cast.
// This should only happen in strange cases like assigning a GroupBase to a Group or in the case
// of a compound type.
IRType symbolType = getDescriptor( type );
if (!(value instanceof IRNullLiteral) &&
!symbolType.isAssignableFrom(value.getType()) &&
!(symbolType == JavaClassIRType.get( char.class ) && value.getType() == JavaClassIRType.get( int.class ) )) {
value = buildCast( symbolType, value );
}
}
}
else if( _stmt().getScope() == null || _stmt().getScope() == GlobalScope.EXECUTION )
{
//## todo: perf: handle case where initialization is unnecessary i.e., var is definitely assigned value in following code branch[es]
// If the scope is request or session, we can't initialize it because we don't want to clobber the current value
value = getDefaultConstIns( type );
}
// If the symbol is boxed, then create an array of size 1 with that value in it
IRType symbolType;
if( symbol.isValueBoxed() && value != null )
{
value = buildInitializedArray( getDescriptor( type ), Collections.singletonList( value ) );
symbolType = getDescriptor( symbol.getType() ).getArrayType();
}
else
{
symbolType = getDescriptor( symbol.getType() );
}
IRStatement assignmentStmt;
if( isProgramVar( symbol ) )
{
// Program var (maintained as a field on the generated class)
assignmentStmt = setInstanceField( getGosuClass(), symbol.getName(), getDescriptor( symbol.getType() ),
AccessibilityUtil.forSymbol( symbol ), pushThis(), value );
}
else if ( _stmt().getScope() == null || _stmt().getScope() == GlobalScope.EXECUTION )
{
// If the scope is request or session, we don't want to store anything on the stack at all.
// Otherwise, we treat this as a local variable
assignmentStmt = buildAssignment( _cc().createSymbol( symbol.getName(), symbolType ), value );
}
else
{
assignmentStmt = new IRNoOpStatement();
}
assignmentStmt.setImplicit( asExp == null );
return assignmentStmt;
}
private boolean isProgramVar( Symbol symbol )
{
return _cc().compilingProgram() && symbol instanceof DynamicSymbol;
}
}