/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.parser.expressions; import gw.internal.gosu.parser.BeanAccess; import gw.internal.gosu.parser.Expression; import gw.internal.gosu.parser.RuntimeExceptionWithNoStacktrace; import gw.internal.gosu.parser.SimpleBeanAccess; import gw.internal.gosu.parser.StringCache; import gw.lang.parser.MemberAccessKind; import gw.internal.gosu.parser.optimizer.SinglePropertyMemberAccessRuntime; import gw.lang.parser.IExpressionRuntime; import gw.lang.parser.exceptions.ParseException; import gw.lang.parser.expressions.IFieldAccessExpression; import gw.lang.reflect.IMetaType; import gw.lang.reflect.IPropertyInfo; import gw.lang.reflect.IType; import gw.lang.reflect.IPropertyInfoDelegate; import gw.lang.reflect.gs.IGosuClass; import gw.lang.reflect.gs.IProgramInstance; import gw.lang.reflect.java.ICompileTimeConstantValue; /** * Represents a member access expression in the Gosu grammar: * <pre> * <i>member-access</i> * <root-expression>.<member> * <root-expression>[member-name] * <p/> * <i>root-expression</i> * <bean-reference> * <type-literal> * <p/> * <i>member</i> * <member-access> * <identifier> * <p/> * <i>bean-reference</i> * <primary-expression> * <p/> * <i>member-name</i> * <expression> * </pre> * * @see gw.lang.parser.IGosuParser */ public class MemberAccess extends Expression implements IFieldAccessExpression, IHasOperatorLineNumber { /** * The root expression in the path (instead of a root bean symbol) */ private Expression _rootExpression; /** * The member name. */ private String _strMemberName; /** * Start offset of array list (without leading '.') */ private int _startOffset; /** * An expression for accessing a member by name dynamically */ private Expression _memberExpression; private IExpressionRuntime _expressionRuntime; private String _strMethodNameForSyntheticAccess; private MemberAccessKind _kind; private int _opLineNum; public Expression getRootExpression() { return _rootExpression; } public Object evaluateRootExpr() { IProgramInstance instance; try { instance = (IProgramInstance)getGosuProgram().getBackingClass().newInstance(); } catch( Exception e ) { throw new RuntimeException( e ); } return instance.evaluateRootExpr(null); } public void setRootExpression( Expression rootExpression ) { _rootExpression = rootExpression; } public String getMemberName() { return _strMemberName; } public void setMemberName( String strMemberName ) { assert strMemberName != null; _strMemberName = StringCache.get(strMemberName); } public int getStartOffset() { return _startOffset; } public void setStartOffset( int startOffset ) { _startOffset = startOffset; } public Expression getMemberExpression() { return _memberExpression; } public void setMemberExpression( Expression memberExpression ) { _memberExpression = memberExpression; } public IType getRootType() { IType rootType = getRootExpression().getType(); rootType = IGosuClass.ProxyUtil.isProxy(rootType) && rootType instanceof IGosuClass ? ((IGosuClass) rootType).getJavaType() : rootType; return rootType; } public IPropertyInfo getPropertyInfo() { if( _memberExpression != null || _strMemberName == null ) { return null; } try { return BeanAccess.getPropertyInfoDirectly( getRootType(), _strMemberName ); } catch( ParseException e ) { throw new RuntimeExceptionWithNoStacktrace( e ); } } public IPropertyInfo getPropertyInfoWithoutThrowing() { if( _memberExpression != null || _strMemberName == null ) { return null; } return SimpleBeanAccess.getPropertyInfoDirectly(getRootType(), _strMemberName); } public String getMethodNameForSyntheticAccess() { return _strMethodNameForSyntheticAccess; } public void setMethodNameForSyntheticAccess( String strName ) { _strMethodNameForSyntheticAccess = strName; } public boolean isCompileTimeConstant() { if( getRootExpression().isCompileTimeConstant() ) { IPropertyInfo pi; try { pi = getCompileTimePropertyInfo(); if( pi == null ) { return false; } } catch( RuntimeException e ) { // Can happen if this expression does not parse / errant property name return false; } if( pi == null ) { return false; } while( pi instanceof IPropertyInfoDelegate ) { pi = ((IPropertyInfoDelegate)pi).getSource(); } if( pi.isStatic() && pi instanceof ICompileTimeConstantValue ) { return ((ICompileTimeConstantValue)pi).isCompileTimeConstantValue(); } } return false; } public Object evaluate() { if( !isCompileTimeConstant() ) { return super.evaluate(); } IPropertyInfo pi = getCompileTimePropertyInfo(); while( pi instanceof IPropertyInfoDelegate ) { pi = ((IPropertyInfoDelegate)pi).getSource(); } return ((ICompileTimeConstantValue)pi).doCompileTimeEvaluation(); } public IPropertyInfo getCompileTimePropertyInfo() { if( _memberExpression != null || _strMemberName == null ) { return null; } try { IType rootType = getRootType(); if (rootType instanceof IMetaType) { rootType = ((IMetaType) rootType).getType(); } return BeanAccess.getPropertyInfoDirectly(rootType, _strMemberName); } catch( ParseException e ) { throw new RuntimeException( e ); } } public void setExpressionRuntime(IExpressionRuntime expressionRuntime) { _expressionRuntime = expressionRuntime; } public IExpressionRuntime getExpressionRuntime() { if( _expressionRuntime == null ) { if( SinglePropertyMemberAccessRuntime.isConvertible( this ) ) { _expressionRuntime = new SinglePropertyMemberAccessRuntime( this ); } } return _expressionRuntime; } public MemberAccessKind getMemberAccessKind() { return _kind; } public void setMemberAccessKind( MemberAccessKind kind ) { _kind = kind; } @Override public boolean isNullSafe() { return getMemberAccessKind() == MemberAccessKind.NULL_SAFE; } @Override public String toString() { return getRootExpression().toString() + "." + _strMemberName; } @Override public int getOperatorLineNumber() { return _opLineNum; } @Override public void setOperatorLineNumber( int operatorLineNumber ) { _opLineNum = operatorLineNumber; } }