/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.parser.statements;
import gw.internal.gosu.parser.CannotExecuteGosuException;
import gw.internal.gosu.parser.DynamicFunctionSymbol;
import gw.internal.gosu.parser.Expression;
import gw.internal.gosu.parser.IGosuAnnotation;
import gw.internal.gosu.parser.ModifierInfo;
import gw.internal.gosu.parser.Statement;
import gw.internal.gosu.parser.expressions.BlockExpression;
import gw.internal.gosu.parser.expressions.TypeLiteral;
import gw.lang.parser.GlobalScope;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.IScriptPartId;
import gw.lang.parser.ISymbol;
import gw.lang.parser.expressions.IVarStatement;
import gw.lang.parser.statements.IClassStatement;
import gw.lang.parser.statements.ITerminalStatement;
import gw.lang.reflect.IFeatureInfo;
import gw.lang.reflect.IType;
import gw.lang.reflect.Modifier;
import gw.util.GosuObjectUtil;
import java.util.Collections;
import java.util.List;
/**
* Represents a var statement as specified in the Gosu grammar:
* <pre>
* <i>var-statement</i>
* <b>var</b> <identifier> [scope-attribute] [ <b>:</b> <type-expression> ] <b>=</b> <expression>
* <b>var</b> <identifier> [scope-attribute] <b>:</b> <type-expression> [ <b>=</b> <expression> ]
* </pre>
* <p/>
*
* @see gw.lang.parser.IGosuParser
*/
public class VarStatement extends Statement implements IVarStatement
{
private String _strPropertyName;
protected Expression _expression;
protected TypeLiteral _typeLiteral;
protected boolean _hasProperty = false;
protected GlobalScope _scope;
protected ModifierInfo _modifiers;
private ISymbol _symbol;
private IScriptPartId _scriptPartId;
private int _iNameOffset;
private int _iPropertyNameOffset;
private boolean _bDefinitionParsed;
private boolean _bIsInitializedTopLevelProgVar;
public VarStatement()
{
}
public String getIdentifierName()
{
return _symbol.getName();
}
public ISymbol getSymbol()
{
return _symbol;
}
public void setSymbol( ISymbol symbol )
{
_symbol = symbol;
}
public String getPropertyName()
{
return _strPropertyName;
}
public void setPropertyName( String strPropertyName )
{
_strPropertyName = strPropertyName;
}
public GlobalScope getScope()
{
return _scope;
}
public void setScope( GlobalScope scope )
{
_scope = scope;
}
public TypeLiteral getTypeLiteral()
{
return _typeLiteral;
}
public void setTypeLiteral( TypeLiteral typeLiteral )
{
detachDeclTypeLiteral();
_typeLiteral = typeLiteral;
}
private void detachDeclTypeLiteral()
{
if( _typeLiteral != null && getLocation() != null )
{
getLocation().removeChild( _typeLiteral.getLocation() );
}
}
public Expression getAsExpression()
{
return _expression;
}
public void setAsExpression( Expression expression )
{
_expression = expression;
}
public void setType( IType newType )
{
_symbol.setType( newType );
}
public boolean hasProperty()
{
return _hasProperty;
}
public void setHasProperty( boolean hasProperty )
{
_hasProperty = hasProperty;
}
public ModifierInfo getModifierInfo()
{
return _modifiers;
}
public void setModifierInfo( ModifierInfo modifiers )
{
_modifiers = modifiers;
}
public int getModifiers()
{
return _modifiers.getModifiers();
}
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() ) || (!isInternal() && !isProtected() && !isPublic());
}
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() );
}
public void setPublic( boolean bPublic )
{
_modifiers.setModifiers( Modifier.setPublic( _modifiers.getModifiers(), bPublic ) );
}
public boolean isFinal()
{
return Modifier.isFinal( getModifiers() );
}
public void setFinal( boolean bFinal )
{
_modifiers.setModifiers( Modifier.setFinal( _modifiers.getModifiers(), bFinal ) );
}
public boolean isEnumConstant() {
return Modifier.isEnum( getModifiers() );
}
public void setEnumConstant( boolean bEnumConstant ) {
_modifiers.setModifiers( Modifier.setEnum( _modifiers.getModifiers(), bEnumConstant ) );
}
public boolean isTransient()
{
return Modifier.isTransient( getModifiers() );
}
public IType getType()
{
return _symbol == null ? null : _symbol.getType();
}
public void setScriptPart( IScriptPartId partId )
{
_scriptPartId = partId;
}
public IScriptPartId getScriptPart()
{
return _scriptPartId;
}
/**
* Executes the Var statement. The algorithm for the execution follows:
* <ol>
* <li> Evaluate the ValueExpression (if one exists).
* <li> Create and map a symbol for the Identifier with type reflecting the ValueExpression's type.
* <li> If a TypeLiteral is specified, set the Identifier's type accordingly.
* </ol>
*/
public Object execute()
{
if( !isCompileTimeConstant() )
{
return super.execute();
}
throw new CannotExecuteGosuException();
}
@Override
protected ITerminalStatement getLeastSignificantTerminalStatement_internal( boolean[] bAbsolute )
{
bAbsolute[0] = false;
return null;
}
@Override
public String toString()
{
return "var " + getIdentifierName() +
(getTypeLiteral() != null ? (" : " + getTypeLiteral().toString()) : "" ) +
(getAsExpression() != null ? (" = " + getAsExpression().toString()) : "" );
}
@Override
public String getFunctionName()
{
if( getParent() instanceof ClassStatement )
{
return "_init";
}
else
{
return super.getFunctionName();
}
}
@Override
public int getNameOffset( String identifierName )
{
return identifierName == null || identifierName.equals( getIdentifierName() )
? _iNameOffset
: identifierName.equals( getPropertyName() )
? _iPropertyNameOffset
: -1;
}
@Override
public void setNameOffset( int iOffset, String identifierName )
{
if( identifierName != null && getPropertyName() != null && identifierName.equals( getPropertyName() ) )
{
_iPropertyNameOffset = iOffset;
}
else
{
_iNameOffset = iOffset;
}
}
public boolean declares( String identifierName )
{
return GosuObjectUtil.equals(getIdentifierName(), identifierName ) ||
GosuObjectUtil.equals(getPropertyName(), identifierName );
}
public String[] getDeclarations() {
if (getPropertyName() == null) {
return new String[] {getIdentifierName().toString()};
} else {
return new String[] {getIdentifierName().toString(), getPropertyName().toString()};
}
}
private IFeatureInfo findOwningFeatureInfoOfDeclaredSymbols( String identifierName)
{
// sct: The only cases that I know of:
// 1. var has no enclosing type, or
// 2. it is a "child" of ClassStatement, or
// 3. it is local to a function or property (i.e. a "child" of FunctionStatement or PropertyStatement), or
// 4. it is local to a block
IParsedElement parsedElement = findAncestorParsedElementByType( ClassStatement.class,
FunctionStatement.class,
PropertyStatement.class,
BlockExpression.class );
if( parsedElement == null )
{
return null;
}
else if( parsedElement instanceof ClassStatement )
{
return ((ClassStatement)parsedElement).getGosuClass().getTypeInfo();
}
else if( parsedElement instanceof FunctionStatement )
{
DynamicFunctionSymbol dfs = ((FunctionStatement)parsedElement).getDynamicFunctionSymbol();
if( dfs != null )
{
return dfs.getMethodOrConstructorInfo();
}
else
{
return null;
}
}
else if( parsedElement instanceof PropertyStatement )
{
return ((PropertyStatement)parsedElement).getPropertyGetterOrSetter().getDynamicFunctionSymbol().getMethodOrConstructorInfo();
}
else
{
return null;
}
}
public List<IGosuAnnotation> getAnnotations()
{
return _modifiers == null
? Collections.<IGosuAnnotation>emptyList()
: _modifiers.getAnnotations();
}
public String getFullDescription()
{
return _modifiers == null ? "" : _modifiers.getDescription();
}
public void clearDefn()
{
_expression = null;
}
public boolean isDefinitionParsed()
{
return _bDefinitionParsed;
}
public void setDefinitionParsed( boolean bParsed )
{
_bDefinitionParsed = bParsed;
}
public boolean getHasInitializer()
{
return _expression != null || _bIsInitializedTopLevelProgVar;
}
public boolean isImplicitlyUsed() {
return !isPrivate() || hasProperty();
}
public int getPropertyNameOffset() {
return _iPropertyNameOffset;
}
@Override
public boolean isFieldDeclaration() {
return getParent() instanceof IClassStatement;
}
public void setIsInitializedTopLevelProgVar() {
_bIsInitializedTopLevelProgVar = true;
}
}