/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.ir.transform.expression; import gw.lang.parser.IExpression; import gw.lang.parser.ICapturedSymbol; import gw.lang.parser.IDynamicFunctionSymbol; import gw.lang.parser.IParsedElement; import gw.lang.parser.statements.IFunctionStatement; import gw.lang.reflect.IType; import gw.lang.reflect.gs.IGenericTypeVariable; import gw.lang.reflect.gs.IGosuClass; import gw.lang.reflect.gs.IGosuProgram; import gw.internal.gosu.parser.ICompilableTypeInternal; import gw.internal.gosu.ir.transform.TopLevelTransformationContext; import gw.internal.gosu.ir.transform.util.AccessibilityUtil; import gw.lang.ir.IRExpression; import gw.lang.ir.IRTypeConstants; import gw.internal.gosu.parser.IGosuClassInternal; import gw.internal.gosu.parser.fragments.GosuFragment; import java.util.List; import java.util.ArrayList; public abstract class EvalBasedTransformer<T extends IExpression> extends AbstractExpressionTransformer<T> { public EvalBasedTransformer( TopLevelTransformationContext cc, T parsedElem ) { super( cc, parsedElem ); } protected IRExpression pushEnclosingContext() { if( !_cc().isCurrentFunctionStatic() ) { return pushThisOrOuter( getGosuClass() ); } else { return pushNull(); } } protected IRExpression pushCapturedSymbols( ICompilableTypeInternal enclosingClass, List<ICapturedSymbol> capturedSymbols ) { List<IRExpression> values = new ArrayList<IRExpression>(); if ( capturedSymbols != null) { for( ICapturedSymbol sym : capturedSymbols ) { if( enclosingClass.isAnonymous() && enclosingClass.getCapturedSymbols().containsKey( sym.getName() ) ) { values.add( getInstanceField( getGosuClass(), CAPTURED_VAR_PREFIX + sym.getName(), getDescriptor( sym.getType().getArrayType() ), AccessibilityUtil.forCapturedVar(), pushThis() ) ); } else { values.add( identifier( _cc().getSymbol( sym.getName() ) ) ); } } } if ( requiresExternalSymbolCapture( enclosingClass ) || enclosingClass instanceof GosuFragment || enclosingClass instanceof IGosuProgram ) { values.add( pushExternalSymbolsMap() ); } if (!values.isEmpty()) { return buildInitializedArray(IRTypeConstants.OBJECT(), values ); } else { return pushNull(); } } protected static void addEnclosingTypeParams( IType[] immediateFuncTypeParams, List<Object> args ) { if( immediateFuncTypeParams != null ) { //noinspection ManualArrayToCollectionCopy for( int i = 0; i < immediateFuncTypeParams.length; i++ ) { args.add( immediateFuncTypeParams[i] ); } } } protected IRExpression pushEnclosingFunctionTypeParamsInArray( IParsedElement expr ) { int iCount = getFunctionTypeParamsCount( expr ); if( iCount == 0 ) { return pushNull(); } List<IRExpression> values = new ArrayList<IRExpression>(); IGosuClassInternal gsClass = null; while( expr != null && expr.getLocation() != null ) { IFunctionStatement funcStmt = expr.getLocation().getEnclosingFunctionStatement(); if( funcStmt != null ) // can be null e.g., anonymous classes can be constructed as field initializers { IDynamicFunctionSymbol dfs = funcStmt.getDynamicFunctionSymbol(); if( dfs.getType().isGenericType() ) { IGenericTypeVariable[] genTypeVars = dfs.getType().getGenericTypeVariables(); for( int i = 0; i < genTypeVars.length; i++ ) { if( gsClass == null ) { values.add( identifier( _cc().getSymbol( getTypeVarParamName( genTypeVars[i]) ) ) ); } else { pushThisOrOuter( gsClass ); values.add( getInstanceField( gsClass, TYPE_PARAM_PREFIX + genTypeVars[i].getName(), IRTypeConstants.ITYPE(), AccessibilityUtil.forTypeParameter(), pushThisOrOuter( gsClass ) ) ); } } return buildInitializedArray(IRTypeConstants.ITYPE(), values ); } } IType type = funcStmt.getDynamicFunctionSymbol().getScriptPart().getContainingType(); if( type instanceof IGosuClass && ((IGosuClass)type).isAnonymous() ) { gsClass = (IGosuClassInternal)type; expr = isEvalProgram( gsClass ) ? ((IGosuProgram)gsClass).getEnclosingEvalExpression() : gsClass.getClassStatement(); } else { expr = null; } } throw new IllegalStateException("Should have found the appropriate enclosing context "); } protected int getFunctionTypeParamsCount( IParsedElement pe ) { IGosuClassInternal gsClass; int iCount = 0; while( pe != null && pe.getLocation() != null ) { IFunctionStatement funcStmt = pe.getLocation().getEnclosingFunctionStatement(); if( funcStmt != null ) // can be null e.g., anonymous classes can be constructed as field initializers { IDynamicFunctionSymbol dfs = funcStmt.getDynamicFunctionSymbol(); if( dfs.getType().isGenericType() ) { IGenericTypeVariable[] genTypeVars = dfs.getType().getGenericTypeVariables(); iCount += genTypeVars.length; } IType type = funcStmt.getDynamicFunctionSymbol().getScriptPart().getContainingType(); if( type instanceof IGosuClass && ((IGosuClass)type).isAnonymous() ) { gsClass = (IGosuClassInternal)type; pe = isEvalProgram( gsClass ) ? ((IGosuProgram)gsClass).getEnclosingEvalExpression() : gsClass.getClassStatement(); } else { pe = null; } } else { pe = null; } } return iCount; } }