/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.parser;
import gw.lang.function.IBlock;
import gw.lang.parser.GlobalScope;
import gw.lang.parser.ICapturedSymbol;
import gw.lang.parser.IExpression;
import gw.lang.parser.IFunctionSymbol;
import gw.lang.parser.IReducedSymbol;
import gw.lang.parser.IScope;
import gw.lang.parser.IScriptPartId;
import gw.lang.parser.IStackProvider;
import gw.lang.parser.ISymbol;
import gw.lang.parser.ISymbolTable;
import gw.lang.parser.Keyword;
import gw.lang.reflect.IModifierInfo;
import gw.lang.reflect.IType;
import gw.lang.reflect.Modifier;
import gw.lang.reflect.gs.IGosuClass;
import gw.util.GosuExceptionUtil;
import gw.util.MutableBoolean;
import java.lang.reflect.Method;
import java.util.List;
/**
* Base class for all symbols in the symbol table.
*/
public class Symbol implements IFunctionSymbol
{
public static final IStackProvider MEMBER_STACK_PROVIDER = new MemberStackProvider();
private String _name;
private IType _type;
protected Object _value;
private IExpression _defaultValue;
protected int _iIndex;
protected boolean _bGlobal;
protected IStackProvider _stackProvider;
protected ISymbolTable _symbolTable;
private MutableBoolean _valueIsBoxed;
private ModifierInfo _modifiers;
public Symbol( String strName, IType type, IStackProvider stackProvider )
{
this( strName, type, stackProvider, null, null );
}
public Symbol( String strName, IType type, IStackProvider stackProvider, Object value )
{
this( strName, type, stackProvider, value, null );
}
public Symbol( String strName, IType type, IStackProvider stackProvider, Object value, IScope scope )
{
setName( strName );
_modifiers = new ModifierInfo(0);
_type = type;
_stackProvider = stackProvider;
_value = value;
_iIndex = assignIndex( scope );
_bGlobal = _stackProvider == null || !_stackProvider.hasIsolatedScope();
_valueIsBoxed = new MutableBoolean();
}
public Symbol( Symbol copy )
{
setName( copy._name );
_type = copy._type;
_iIndex = copy._iIndex;
_bGlobal = copy._bGlobal;
_stackProvider = copy._stackProvider;
_symbolTable = copy._symbolTable;
// We need to use a MutableBoolean here so that modifications are set on all copies.
_valueIsBoxed = copy._valueIsBoxed;
_modifiers = copy._modifiers;
}
/*
* Symbols created via these ctors go to the symbol table, they are not stack based.
*/
public Symbol( String strName, IType type, Object value )
{
this( strName, type, null, value, null );
}
public void setDynamicSymbolTable( ISymbolTable symTable )
{
if( _stackProvider == null )
{
_symbolTable = symTable;
}
}
public boolean hasDynamicSymbolTable()
{
return _symbolTable != null;
}
public ISymbolTable getDynamicSymbolTable()
{
return _symbolTable;
}
protected int assignIndex( IScope scope )
{
return assignIndexInStack( scope );
}
protected int assignIndexInStack( IScope scope )
{
if( THIS.equals( _name ) )
{
return IStackProvider.THIS_POS;
}
if( SUPER.equals( _name ) )
{
return IStackProvider.SUPER_POS;
}
if( _stackProvider == null )
{
return -1;
}
else
{
if( scope == null )
{
return _stackProvider.getNextStackIndex();
}
else
{
return _stackProvider.getNextStackIndexForScope( scope );
}
}
}
/**
* Returns the Symbol's name.
*/
public String getName()
{
return _name;
}
/**
* Returns the Symbol's optional display name. If a display name is not assigned,
* returns the symbol's name.
*/
public String getDisplayName()
{
return getName();
}
@Override
public String getFullDescription()
{
return null;
}
public void renameAsErrantDuplicate( int iIndex )
{
setName( (String)(iIndex + "_duplicate_" + getName()) );
}
/**
* Returns the Symbol's type.
*/
public IType getType()
{
return _type;
}
/**
* Sets the Symbol's type.
*/
public void setType( IType type )
{
_type = type;
}
/**
* Returns the value assigned to this Symbol.
*/
public Object getValue()
{
if( _symbolTable != null )
{
return getValueFromSymbolTable();
}
return _value;
}
private Object getValueFromSymbolTable()
{
ISymbol symbol = _symbolTable.getSymbol( _name );
if( symbol instanceof Symbol )
{
return ((Symbol)symbol).getValueDirectly();
}
if( symbol != null )
{
return symbol.getValue();
}
return _value;
}
/**
* Assigns a value to this Symbol.
*/
public void setValue( Object value )
{
if( _symbolTable != null )
{
setValueFromSymbolTable( value );
}
else
{
_value = value;
}
}
public IExpression getDefaultValueExpression()
{
return _defaultValue;
}
public void setDefaultValueExpression( IExpression defaultValue )
{
_defaultValue = defaultValue;
}
public boolean isStackSymbol()
{
return _stackProvider != null && _stackProvider != MEMBER_STACK_PROVIDER && !_bGlobal;
}
private void setValueFromSymbolTable( Object value )
{
ISymbol symbol = _symbolTable.getSymbol( _name );
((Symbol)symbol).setValueDirectly( value );
}
public Object getValueDirectly()
{
return _value;
}
public void setValueDirectly( Object value )
{
_value = value;
}
/**
* Invokes function.
*/
public Object invoke( Object[] args )
{
Object value = getValue();
if( value instanceof ISymbol )
{
return ((Symbol)value).invoke( args );
}
if( value instanceof IBlock )
{
return ((IBlock) value).invokeWithArgs( args );
}
Method method = (Method)value;
Object ret;
try
{
ret = method.invoke( null, args );
}
catch( Exception e )
{
throw GosuExceptionUtil.forceThrow( e );
}
return ret;
}
public ISymbol getLightWeightReference()
{
if( _symbolTable == null &&
_stackProvider == null || _stackProvider == MEMBER_STACK_PROVIDER )
{
return this;
}
return new Symbol( this );
}
public boolean isImplicitlyInitialized() {
return false;
}
public boolean isWritable()
{
return !isFinal();
}
public boolean equals( Object o )
{
if( this == o )
{
return true;
}
if( !(o instanceof Symbol) )
{
return false;
}
final Symbol symbol = (Symbol)o;
if( !_name.equals( symbol._name ) )
{
return false;
}
if( _type != null ? !_type.equals( symbol._type ) : symbol._type != null )
{
return false;
}
return !(_value != null ? !_value.equals( symbol._value ) : symbol._value != null);
}
public String getSignatureDescription()
{
return null;
}
public int getIndex()
{
return _iIndex;
}
public boolean isClassMember()
{
return Modifier.isClassMember( _modifiers.getModifiers() );
}
public void setClassMember( boolean bClassMember )
{
_modifiers.setModifiers( Modifier.setClassMember( _modifiers.getModifiers(), bClassMember ) );
}
public boolean isStatic()
{
return Modifier.isStatic( _modifiers.getModifiers() );
}
public void setStatic( boolean bStatic )
{
_modifiers.setModifiers( Modifier.setStatic( _modifiers.getModifiers(), bStatic ) );
}
public boolean isPrivate()
{
return Modifier.isPrivate( _modifiers.getModifiers() );
}
public void setPrivate( boolean bPrivate )
{
_modifiers.setModifiers( Modifier.setPrivate( _modifiers.getModifiers(), bPrivate ) );
}
public boolean isInternal()
{
return Modifier.isInternal( _modifiers.getModifiers() );
}
public void setInternal( boolean bInternal )
{
_modifiers.setModifiers( Modifier.setInternal( _modifiers.getModifiers(), bInternal ) );
}
public boolean isProtected()
{
return Modifier.isProtected( _modifiers.getModifiers() );
}
public void setProtected( boolean bProtected )
{
_modifiers.setModifiers( Modifier.setProtected( _modifiers.getModifiers(), bProtected ) );
}
public boolean isPublic()
{
return Modifier.isPublic( _modifiers.getModifiers() ) || (!isPrivate() && !isProtected() && !isInternal());
}
public void setPublic( boolean bPublic )
{
_modifiers.setModifiers( Modifier.setPublic( _modifiers.getModifiers(), bPublic ) );
}
public boolean isAbstract()
{
return Modifier.isAbstract( _modifiers.getModifiers() );
}
public void setAbstract( boolean bAbstract )
{
_modifiers.setModifiers( Modifier.setAbstract( _modifiers.getModifiers(), bAbstract ) );
}
public boolean isFinal()
{
return Modifier.isFinal( _modifiers.getModifiers() );
}
public void setFinal( boolean bFinal )
{
_modifiers.setModifiers( Modifier.setFinal( _modifiers.getModifiers(), bFinal ) );
}
public boolean isOverride()
{
return Modifier.isOverride( _modifiers.getModifiers() );
}
public void setOverride( boolean bOverride )
{
_modifiers.setModifiers( Modifier.setOverride( _modifiers.getModifiers(), bOverride ) );
}
public boolean isHide()
{
return Modifier.isHide( _modifiers.getModifiers() );
}
public void setHide( boolean bHide )
{
_modifiers.setModifiers( Modifier.setHide( _modifiers.getModifiers(), bHide ) );
}
public ModifierInfo getModifierInfo()
{
return _modifiers;
}
public void setModifierInfo( IModifierInfo modifiers )
{
if( _modifiers == null )
{
_modifiers = (ModifierInfo) modifiers;
}
else
{
_modifiers.update((ModifierInfo) modifiers);
}
}
public void replaceModifierInfo( IModifierInfo mi )
{
_modifiers = (ModifierInfo) mi;
}
public int getModifiers()
{
return _modifiers.getModifiers();
}
public List<IGosuAnnotation> getAnnotations()
{
return getModifierInfo().getAnnotations();
}
@Override
public IScriptPartId getScriptPart() {
return null;
}
@Override
public IGosuClass getGosuClass() {
return null;
}
@Override
public boolean hasTypeVariables() {
return false;
}
@Override
public GlobalScope getScope() {
return null;
}
public void setModifiers( int modifiers )
{
_modifiers.setModifiers( modifiers );
}
public String toString()
{
Object value;
try
{
value = getValue();
}
catch( Exception e )
{
value = "Undefined";
}
return getName() + " : " + getType() + ": " + " = " + value;
}
public boolean canBeCaptured()
{
return isStackSymbol() &&
!getName().equals( Keyword.KW_this.toString() ) &&
!getName().equals( Keyword.KW_super.toString() );
}
public ICapturedSymbol makeCapturedSymbol( String strName, ISymbolTable symbolTable, IScope scope )
{
return new CapturedSymbol( strName, this, symbolTable, scope );
}
public void setIndex( int i )
{
_iIndex = i;
}
/** */
private static class MemberStackProvider implements IStackProvider
{
public int getNextStackIndex()
{
return -1;
}
public int getNextStackIndexForScope( IScope scope )
{
return -1;
}
public boolean hasIsolatedScope()
{
return true;
}
}
public void setValueIsBoxed( boolean b )
{
_valueIsBoxed.setValue( b );
}
public boolean isValueBoxed()
{
return _valueIsBoxed.isTrue();
}
protected void setName( String name )
{
_name = name;
}
@Override
public boolean isLocal()
{
return _iIndex >= 0;
}
@Override
public boolean isFromJava()
{
return false;
}
public Class getSymbolClass()
{
return getClass();
}
public IReducedSymbol createReducedSymbol()
{
return new ReducedSymbol(this);
}
}