/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.ir.transform.statement; import gw.internal.gosu.parser.BeanAccess; import gw.internal.gosu.parser.Expression; import gw.internal.gosu.parser.Statement; import gw.internal.gosu.parser.statements.CaseClause; import gw.internal.gosu.parser.statements.SwitchStatement; import gw.internal.gosu.ir.transform.ExpressionTransformer; import gw.internal.gosu.ir.transform.TopLevelTransformationContext; import gw.lang.ir.IRStatement; import gw.lang.ir.IRSymbol; import gw.lang.ir.IRExpression; import gw.lang.ir.statement.IRCaseClause; import gw.lang.ir.statement.IRSwitchStatement; import gw.lang.reflect.IType; import gw.lang.reflect.java.IJavaType; import gw.lang.reflect.java.JavaTypes; import gw.lang.reflect.java.JavaTypes; import java.util.List; import java.util.ArrayList; /** */ public class SwitchStatementTransformer extends AbstractStatementTransformer<SwitchStatement> { public static IRStatement compile( TopLevelTransformationContext cc, SwitchStatement stmt ) { SwitchStatementTransformer compiler = new SwitchStatementTransformer( cc, stmt ); return compiler.compile(); } private SwitchStatementTransformer( TopLevelTransformationContext cc, SwitchStatement stmt ) { super( cc, stmt ); } @Override protected IRStatement compile_impl() { IType switchType = _stmt().getSwitchExpression().getType(); // To initialize the switch statement, we assign the root to a temp variable IRExpression root = ExpressionTransformer.compile( _stmt().getSwitchExpression(), _cc() ); IRSymbol tempRoot = _cc().makeAndIndexTempSymbol( root.getType() ); IRStatement init = buildAssignment( tempRoot, root ); List<IRCaseClause> irCases = new ArrayList<IRCaseClause>(); CaseClause[] cases = _stmt().getCases(); if( cases != null && cases.length > 0 ) { for( int i = 0; i < cases.length; i++ ) { Expression caseExpression = cases[i].getExpression(); IRExpression caseTest; if( (isIntType( switchType ) || switchType == JavaTypes.pBOOLEAN()) && (isIntType( caseExpression.getType() ) || caseExpression.getType() == JavaTypes.pBOOLEAN()) ) { caseTest = compileCaseExpr_int( tempRoot, caseExpression ); } else { caseTest = compileCaseExpr_ref( switchType, tempRoot, caseExpression ); } List<Statement> caseStatements = cases[i].getStatements(); List<IRStatement> irCaseStatements = new ArrayList<IRStatement>(); if( caseStatements != null ) { _cc().pushScope( false ); try { for( Statement caseStatement : caseStatements ) { irCaseStatements.add( _cc().compile( caseStatement ) ); } } finally { _cc().popScope(); } } irCases.add( new IRCaseClause( caseTest, irCaseStatements ) ); } } List<Statement> defaultStmts = _stmt().getDefaultStatements(); List<IRStatement> irDefaultStatements = new ArrayList<IRStatement>(); if( defaultStmts != null && !defaultStmts.isEmpty() ) { // Push a scope so that locals don't bleed through to the next case //## todo: er, do the same thing in the parser since it's really not quite legal for (Statement defaultStatement : defaultStmts) { irDefaultStatements.add( _cc().compile( defaultStatement ) ); } } return new IRSwitchStatement( init, irCases, irDefaultStatements ); } private IRExpression compileCaseExpr_int( IRSymbol tempRoot, Expression caseExpression ) { return buildEquals( identifier( tempRoot ), ExpressionTransformer.compile( caseExpression, _cc() ) ); } private IRExpression compileCaseExpr_ref( IType switchType, IRSymbol tempRoot, Expression caseExpression ) { if( switchType == caseExpression.getType() && isBytecodeType( switchType ) ) { return callStaticMethod( getClass(), "areEqual", new Class[]{Object.class, Object.class}, exprList( identifier( tempRoot ), ExpressionTransformer.compile( caseExpression, _cc() ) ) ); } else { return callStaticMethod( BeanAccess.class, "areValuesEqual", new Class[]{IType.class, Object.class, IType.class, Object.class}, exprList( pushType( switchType ), identifier( tempRoot ), pushType( caseExpression.getType() ), ExpressionTransformer.compile( caseExpression, _cc() ) )); } } public static boolean areEqual( Object p1, Object p2 ) { return (p1 == null && p2 == null) || (p1 != null && p2 != null && p1.equals( p2 )); } }