/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.ir.transform.expression; import gw.internal.gosu.ir.nodes.IRMethod; import gw.internal.gosu.ir.nodes.IRMethodFactory; import gw.internal.gosu.ir.transform.ExpressionTransformer; import gw.internal.gosu.ir.transform.TopLevelTransformationContext; import gw.internal.gosu.parser.Expression; import gw.internal.gosu.parser.expressions.NewExpression; import gw.lang.ir.IRElement; import gw.lang.ir.IRExpression; import gw.lang.ir.IRSymbol; import gw.lang.ir.expression.IRCompositeExpression; import gw.lang.ir.expression.IRNewMultiDimensionalArrayExpression; import gw.lang.parser.expressions.IInitializerExpression; import gw.lang.reflect.IConstructorHandler; import gw.lang.reflect.IConstructorInfo; import gw.lang.reflect.IRelativeTypeInfo; import gw.lang.reflect.IType; import gw.lang.reflect.ITypeInfo; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** */ public class NewExpressionTransformer extends AbstractExpressionTransformer<NewExpression> { public static IRExpression compile( TopLevelTransformationContext cc, NewExpression expr ) { NewExpressionTransformer compiler = new NewExpressionTransformer( cc, expr ); return compiler.compile(); } private NewExpressionTransformer( TopLevelTransformationContext cc, NewExpression expr ) { super( cc, expr ); } protected IRExpression compile_impl() { IConstructorInfo ci = _expr().getConstructor(); if( !_expr().getType().isArray() ) { // Constructor invocation // e.g., new Foo() return compileConstructorCall( ci ); } else if( _expr().getValueExpressions() != null ) { // Array construction with intialization // e.g., new String[] {"a", "b", "c"} return compileArrayInitialization( ); } else if( _expr().getSizeExpressions() != null ) { // Array construction with size[s] // e.g., new long[5][] // e.g., new String[5][8][] return compileArrayConstruction( ); } else { // Array construction with empty intialization // e.g., new String[] {} IType atomicType = _expr().getType().getComponentType(); if( isBytecodeType( atomicType ) ) { return newArray( getDescriptor( atomicType ), pushConstant( 0 ) ); } else { return makeArrayViaTypeInfo( atomicType, Collections.<Expression>emptyList() ); } } } private IRExpression compileArrayConstruction( ) { List<Expression> sizeExpressions = _expr().getSizeExpressions(); IType atomicType = _expr().getType().getComponentType(); if( isBytecodeType( atomicType ) ) { if( sizeExpressions.size() == 1 ) { Expression sizeExpr = sizeExpressions.get( 0 ); return newArray( getDescriptor( atomicType ), ExpressionTransformer.compile( sizeExpr, _cc() ) ); } else { List<IRExpression> irSizeExpressions = new ArrayList<IRExpression>(); for( int i = 0; i < sizeExpressions.size(); i++ ) { irSizeExpressions.add( ExpressionTransformer.compile( sizeExpressions.get( i ), _cc() ) ); } return new IRNewMultiDimensionalArrayExpression( getDescriptor( _expr().getType() ), irSizeExpressions ); } } else { return makeEmptyArrayViaTypeInfo( atomicType, sizeExpressions ); } } private IRExpression compileArrayInitialization( ) { List<Expression> valueExpressions = _expr().getValueExpressions(); IType atomicType = _expr().getType().getComponentType(); if( isBytecodeType( atomicType ) ) { List<IRExpression> irValueExpressions = new ArrayList<IRExpression>(); for( int i = 0; i < valueExpressions.size(); i++ ) { irValueExpressions.add( ExpressionTransformer.compile( valueExpressions.get( i ), _cc() ) ); } return buildInitializedArray( getDescriptor( atomicType ), irValueExpressions ); } else { return makeArrayViaTypeInfo( atomicType, valueExpressions ); } } private IRExpression compileConstructorCall( IConstructorInfo ci ) { IType type = _expr().getType(); IRMethod irConstructor = IRMethodFactory.createIRMethod( ci ); IRExpression constructorCall; List<IRElement> newExprElements; if( irConstructor.isBytecodeMethod() && isBytecodeType( type ) && !_cc().shouldUseReflection( irConstructor.getOwningIType(), irConstructor.getAccessibility() ) ) { List<IRExpression> explicitArgs = new ArrayList<IRExpression>(); pushArgumentsWithCasting( irConstructor, _expr().getArgs(), explicitArgs ); newExprElements = handleNamedArgs( explicitArgs, _expr().getNamedArgOrder() ); // Invoke the constructor List<IRExpression> args = new ArrayList<IRExpression>(); if( isNonStaticInnerClass( type ) ) { args.add( pushThisOrOuter( type.getEnclosingType() ) ); } pushCapturedSymbols( type, args, false ); pushTypeParametersForConstructor( _expr(), type, args ); _cc().pushEnumNameAndOrdinal( type, args ); args.addAll( explicitArgs ); constructorCall = buildNewExpression( getDescriptor( type ), irConstructor.getAllParameterTypes(), args ); } else { List<IRExpression> explicitArgs = new ArrayList<IRExpression>(); pushArgumentsNoCasting( irConstructor, _expr().getArgs(), explicitArgs ); newExprElements = handleNamedArgs( explicitArgs, _expr().getNamedArgOrder() ); // Call the IConstructorInfo dynamically constructorCall = callConstructorInfo( type, ci, explicitArgs ); } if( newExprElements.size() > 0 ) { // Include temp var assignments so named args are evaluated in lexical order before the ctor call newExprElements.add( constructorCall ); constructorCall = new IRCompositeExpression( newExprElements ); } IInitializerExpression initializer = _expr().getInitializer(); if( initializer != null ) { // If there's an initializer, save the result of the constructor to a temp symbol, execute the initializer // statements, and then load the temp symbol back so it's the result of the expression IRSymbol tempSymbol = _cc().makeAndIndexTempSymbol( constructorCall.getType() ); List<IRElement> constructorElements = new ArrayList<IRElement>(); constructorElements.add( buildAssignment( tempSymbol, constructorCall ) ); constructorElements.addAll( ExpressionTransformer.compileInitializer( initializer, _cc(), identifier( tempSymbol ) ) ); constructorElements.add( identifier( tempSymbol ) ); constructorCall = new IRCompositeExpression( constructorElements ); } return constructorCall; } private IRExpression callConstructorInfo( IType rootType, IConstructorInfo ci, List<IRExpression> explicitArgs ) { // // rootType // .getTypeInfo() // .getConstructor( argTypes ) // .getConstructor() // .newInstance( args ) // IRExpression typeInfo = callMethod( IType.class, "getTypeInfo", new Class[0], pushType( rootType ), exprList() ); IRExpression constructorInfo; boolean relativeTypeInfo = ci.getOwnersType().getTypeInfo() instanceof IRelativeTypeInfo; if( relativeTypeInfo ) { typeInfo = checkCast( IRelativeTypeInfo.class, typeInfo ); constructorInfo = callMethod( IRelativeTypeInfo.class, "getConstructor", new Class[]{IType.class, IType[].class}, typeInfo, exprList( pushType( rootType ), pushParamTypes( ci.getParameters() ))); } else { constructorInfo = callMethod( ITypeInfo.class, "getConstructor", new Class[]{IType[].class}, typeInfo, exprList( pushParamTypes( ci.getParameters() ) ) ); } IRExpression constructorHandler = callMethod( IConstructorInfo.class, "getConstructor", new Class[0], constructorInfo, exprList() ); IRExpression instance = callMethod( IConstructorHandler.class, "newInstance", new Class[]{Object[].class}, constructorHandler, exprList( collectArgsIntoObjArray( explicitArgs ) ) ); return checkCast( rootType, instance ); } }