/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.ir.transform.expression; import gw.config.CommonServices; import gw.internal.gosu.parser.expressions.MapAccess; import gw.internal.gosu.ir.transform.ExpressionTransformer; import gw.internal.gosu.ir.transform.TopLevelTransformationContext; import gw.lang.ir.IRExpression; import gw.lang.ir.IRSymbol; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.java.JavaTypes; import java.util.Map; import java.util.AbstractMap; /** */ public class MapAccessTransformer extends AbstractExpressionTransformer<MapAccess> { public static IRExpression compile( TopLevelTransformationContext cc, MapAccess expr ) { MapAccessTransformer compiler = new MapAccessTransformer( cc, expr ); return compiler.compile(); } private MapAccessTransformer( TopLevelTransformationContext cc, MapAccess expr ) { super( cc, expr ); } protected IRExpression compile_impl() { // Since we need to short-circuit if the root evaluates to null, we store it in a temp variable // and return a ternary expression, so the result looks like: // temp = root // (temp == null ? null : temp.get(key)) boolean bStandardGosu = CommonServices.getEntityAccess().getLanguageLevel().isStandard(); boolean bNullSafe = _expr().isNullSafe() || !bStandardGosu; IRExpression root = ExpressionTransformer.compile( _expr().getRootExpression(), _cc() ); IRSymbol temp = bNullSafe ? _cc().makeAndIndexTempSymbol( root.getType() ) : null; IRExpression key = ExpressionTransformer.compile( _expr().getKeyExpression(), _cc() ); Class clsMap = getMapType(); IRExpression getCall = callMethod( clsMap, "get", new Class[]{Object.class}, bNullSafe ? identifier( temp ) : root, exprList( key ) ); if( bNullSafe ) { return buildComposite( buildAssignment( temp, root), buildNullCheckTernary( identifier( temp ), checkCast( _expr().getType(), nullLiteral()), checkCast( _expr().getType(), getCall ) ) ); } else { return checkCast( _expr().getType(), getCall ); } } private Class getMapType() { Class clsMap; if( JavaTypes.getJreType(AbstractMap.class).isAssignableFrom( _expr().getRootExpression().getType() ) ) { // Use class instead of interface i.e., invokevirtual is faster than invokeinterface clsMap = AbstractMap.class; } else { clsMap = Map.class; } return clsMap; } }