/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.parser;
import gw.internal.gosu.parser.expressions.BlockExpression;
import gw.internal.gosu.parser.statements.ReturnStatement;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.IStatement;
import gw.lang.parser.statements.IFunctionStatement;
import gw.lang.parser.statements.INoOpStatement;
import gw.lang.parser.statements.IStatementList;
import gw.lang.parser.statements.ITerminalStatement;
import gw.lang.reflect.IType;
import gw.lang.reflect.gs.IExternalSymbolMap;
import gw.lang.reflect.gs.IProgramInstance;
import gw.util.GosuExceptionUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
/**
* The root class for all Statements represented in a parse tree. As specified
* in the Gosu grammar.
*
* @see gw.lang.parser.IGosuParser
*/
public abstract class Statement extends ParsedElement implements IStatement
{
private static final LeastSigTerminal EMPTY_LST = new LeastSigTerminal( null, false );
public static final Object VOID_RETURN_VALUE = new Object(){};
private LeastSigTerminal _cachedLeastSigTerm;
public Statement()
{
}
@Override
public Object execute()
{
Class<?> cls = getGosuProgram().getBackingClass();
try
{
return ((IProgramInstance)cls.newInstance()).evaluate(null);
}
catch( Exception e )
{
throw GosuExceptionUtil.forceThrow( e );
}
}
@Override
public Object execute(IExternalSymbolMap externalSymbols)
{
Class<?> cls = getGosuProgram().getBackingClass();
try
{
return ((IProgramInstance)cls.newInstance()).evaluate(externalSymbols);
}
catch( Exception e )
{
throw GosuExceptionUtil.forceThrow( e );
}
}
/**
* Subclasses should return a String representing the parsed statement.
*/
public abstract String toString();
public boolean isNoOp()
{
return false;
}
public IType getReturnType()
{
ArrayList returnStatements = new ArrayList<ReturnStatement>();
ArrayList<IType> returnTypes = new ArrayList<IType>();
getContainedParsedElementsByTypesWithIgnoreSet( returnStatements, new HashSet(getExcludedReturnTypeElements()), ReturnStatement.class );
for( int i = 0; i < returnStatements.size(); i++ )
{
ReturnStatement returnStmt = (ReturnStatement)returnStatements.get( i );
returnTypes.add( returnStmt.getValue().getType() );
}
return TypeLord.findLeastUpperBound( returnTypes );
}
protected List getExcludedReturnTypeElements()
{
return Arrays.asList(IFunctionStatement.class, BlockExpression.class);
}
public boolean hasContent()
{
if( this instanceof IStatementList )
{
IStatement[] statements = ((IStatementList)this).getStatements();
if( statements != null )
{
for( int i = 0; i < statements.length; i++ )
{
IStatement statement = statements[i];
if( !(statement instanceof INoOpStatement) )
{
return true;
}
}
}
return false;
}
else
{
return !(this instanceof INoOpStatement);
}
}
@Override
public void setParent( IParsedElement rootElement )
{
super.setParent( rootElement );
_cachedLeastSigTerm = null;
}
@Override
public final ITerminalStatement getLeastSignificantTerminalStatement( boolean[] bAbsolute ) {
if( _cachedLeastSigTerm == null ) {
ITerminalStatement stmt = getLeastSignificantTerminalStatement_internal( bAbsolute );
if( stmt == null ) {
_cachedLeastSigTerm = EMPTY_LST;
}
else {
_cachedLeastSigTerm = new LeastSigTerminal( stmt, bAbsolute[0] );
}
}
bAbsolute[0] = _cachedLeastSigTerm._bAbsolute;
return _cachedLeastSigTerm._stmt;
}
protected abstract ITerminalStatement getLeastSignificantTerminalStatement_internal( boolean[] bAbsolute );
public static ITerminalStatement getLeastSignificant( ITerminalStatement... termStmts ) {
ITerminalStatement ret = null;
for( ITerminalStatement stmt : termStmts ) {
if( stmt != null ) {
ret = ret == null
? stmt
: ret.getTerminalType().ordinal() < stmt.getTerminalType().ordinal()
? ret
: stmt;
}
}
return ret;
}
private static class LeastSigTerminal {
private ITerminalStatement _stmt;
private boolean _bAbsolute;
public LeastSigTerminal( ITerminalStatement stmt, boolean bAbsolute ) {
_stmt = stmt;
_bAbsolute = bAbsolute;
}
}
}