/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.parser.statements; import gw.internal.gosu.parser.CannotExecuteGosuException; import gw.internal.gosu.parser.Expression; import gw.internal.gosu.parser.Statement; import gw.internal.gosu.parser.Symbol; import gw.lang.parser.IExpression; import gw.lang.parser.IStackProvider; import gw.lang.parser.ISymbolTable; import gw.lang.parser.statements.IAssertStatement; import gw.lang.parser.statements.IForEachStatement; import gw.lang.parser.statements.ILoopStatement; import gw.lang.parser.statements.IReturnStatement; import gw.lang.parser.statements.ITerminalStatement; import gw.lang.parser.statements.IThrowStatement; import gw.util.GosuObjectUtil; /** * Represents a foreach statement as specified in the Gosu grammar: * <pre> * <i>for...in-statement</i> * <b>for</b> <b>(</b> <identifier> <b>in</b> <expression> [ <b>index</b> <identifier> ] <b>)</b> <statement> * </pre> * <p/> * * @see gw.lang.parser.IGosuParser */ public final class ForEachStatement extends LoopStatement implements IForEachStatement { protected Symbol _identifier; protected Expression _expression; protected Symbol _indexIdentifier; private Symbol _iterIdentifier; protected Statement _statement; protected IStackProvider _stackProvider; private int _iIdentifierOffset; private int _iIndexIdentifierOffset; private int _iIterOffset; private boolean _bStructuralIterable; /** * Constructs a ForEachStatement given an ISymbolTable instance. */ public ForEachStatement( ISymbolTable stackProvider ) { _stackProvider = stackProvider; } /** * @return The name of the Indentifier in the statement. */ public Symbol getIdentifier() { return _identifier; } /** * @param identifier */ public void setIdentifier( Symbol identifier ) { _identifier = identifier; } /** * @return The name of the Index Identifier, or null of not specified. */ public Symbol getIndexIdentifier() { return _indexIdentifier; } /** * @param indexIdentifier */ public void setIndexIdentifier( Symbol indexIdentifier ) { _indexIdentifier = indexIdentifier; } /** * @return The name of the Index Identifier, or null of not specified. */ public Symbol getIteratorIdentifier() { return _iterIdentifier; } public void setIteratorIdentifier( Symbol iterIdentifier ) { _iterIdentifier = iterIdentifier; } @Override public IExpression getExpression() { return getInExpression(); } /** * @return The In Expression. */ public Expression getInExpression() { return _expression; } /** * @param expression The In Expression. */ public void setInExpression( Expression expression ) { _expression = expression; } /** * @return The statement to execute in the interation. */ public Statement getStatement() { return _statement; } /** * @param statement The statement to execute in the interation. */ public void setStatement( Statement statement ) { _statement = statement; if( _statement instanceof StatementList ) { // Use this for-stmt's scope. This is purely a performance feature and not // without a drawback -- in the debugger this for-stmt's scope may have // residual symbols from the execution of its statement-list. This is // really only an issue in the debugger where one may see symbols that are // left over from the previous step in the loop. ((StatementList)_statement).setNoScope(); } } public Object execute() { if( !isCompileTimeConstant() ) { return super.execute(); } throw new CannotExecuteGosuException(); } @Override protected ITerminalStatement getLeastSignificantTerminalStatement_internal( boolean[] bAbsolute ) { if( _statement != null ) { ITerminalStatement terminalStmt = _statement.getLeastSignificantTerminalStatement( bAbsolute ); if( terminalStmt instanceof IReturnStatement || terminalStmt instanceof IAssertStatement || terminalStmt instanceof IThrowStatement || terminalStmt instanceof ILoopStatement ) { bAbsolute[0] = false; return terminalStmt; } } return null; } @Override public String toString() { String strIndex = _indexIdentifier == null ? null : _indexIdentifier.getName(); if( strIndex != null ) { strIndex = " index " + strIndex; } else { strIndex = ""; } return "for( " + (getIdentifier() == null ? "" : getIdentifier().getName()) + " in " + toString(getInExpression()) + strIndex + ")\n" + toString(getStatement()); } private String toString(Object o) { return o == null ? "" : o.toString(); } @Override public int getNameOffset( String identifierName ) { if (identifierName.toString().equals(_identifier.getName())) { return _iIdentifierOffset; } else if (identifierName.toString().equals(_indexIdentifier.getName())) { return _iIndexIdentifierOffset; } else if (identifierName.toString().equals(_iterIdentifier.getName())) { return _iIterOffset; } else { throw new RuntimeException("Wrong name " + identifierName); } } @Override public void setNameOffset( int iOffset, String identifierName ) { _iIdentifierOffset = iOffset; } public void setIndexNameOffset( int iOffset ) { _iIndexIdentifierOffset = iOffset; } public void setIterNameOffset( int iOffset ) { _iIterOffset = iOffset; } public boolean declares( String identifierName ) { return ((getIdentifier() != null) && GosuObjectUtil.equals( getIdentifier().getName(), identifierName )) || ((getIndexIdentifier() != null) && GosuObjectUtil.equals( getIndexIdentifier().getName(), identifierName )) || ((getIteratorIdentifier() != null) && GosuObjectUtil.equals( getIteratorIdentifier().getName(), identifierName )); } public String[] getDeclarations() { if (getIndexIdentifier() != null) { return new String[] {getIdentifier().getName(), getIndexIdentifier().getName()}; } else if (getIdentifier() != null) { return new String[] {getIdentifier().getName()}; } else if (getIteratorIdentifier() != null) { return new String[] {getIteratorIdentifier().getName()}; } else { return new String[1]; } } public boolean isStructuralIterable() { return _bStructuralIterable; } public void setStructuralIterable( boolean bStructuralIterable ) { _bStructuralIterable = bStructuralIterable; } }