/* * 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.lang.parser.statements.IBreakStatement; import gw.lang.parser.statements.ISwitchStatement; import gw.lang.parser.statements.ITerminalStatement; import java.util.List; /** * Represents a switch-statement as specified in the Gosu grammar: * <pre> * <i>switch-statement</i> * <b>switch</b> <b>(</b><expression><b>) {</b> [switch-cases] [switch-default] <b>}</b> * <p/> * <i>switch-cases</i> * <switch-case> * <switch-cases> <switch-case> * <p/> * <i>switch-case</i> * <b>case</b> <expression> <b>:</b> [statement-list] * <p/> * <i>switch-default</i> * <b>default</b> <b>:</b> [statement-list] * </pre> * <p/> * * @see gw.lang.parser.IGosuParser */ public final class SwitchStatement extends Statement implements ISwitchStatement { protected Expression _switchExpression; protected CaseClause[] _cases; protected List<Statement> _defaultStatements; public Expression getSwitchExpression() { return _switchExpression; } public void setSwitchExpression( Expression switchExpression ) { _switchExpression = switchExpression; } public CaseClause[] getCases() { return _cases; } public void setCases( CaseClause[] cases ) { _cases = cases; } public List<Statement> getDefaultStatements() { return _defaultStatements; } public void setDefaultStatements( List<Statement> defaultStatements ) { _defaultStatements = defaultStatements; } /** * Execute the switch statement */ public Object execute() { if( !isCompileTimeConstant() ) { return super.execute(); } throw new CannotExecuteGosuException(); } /** * bAbsolute is true iff there are no break terminals anywhere in any cases and * the default clause's terminator is non-break and absolute */ @Override protected ITerminalStatement getLeastSignificantTerminalStatement_internal( boolean[] bAbsolute ) { ITerminalStatement termRet = null; bAbsolute[0] = true; boolean bBreak = false; if( _cases != null ) { for( int i = 0; i < _cases.length; i++ ) { List caseStatements = _cases[i].getStatements(); if( caseStatements != null && caseStatements.size() > 0 ) { boolean bCaseAbs = true; for( int iStmt = 0; iStmt < caseStatements.size(); iStmt++ ) { boolean[] bCsr = {false}; ITerminalStatement terminalStmt = ((Statement)caseStatements.get( iStmt )).getLeastSignificantTerminalStatement( bCsr ); if( terminalStmt != null ) { bCaseAbs = bCsr[0]; if( !(terminalStmt instanceof IBreakStatement) ) { termRet = getLeastSignificant( termRet, terminalStmt ); } else { bAbsolute[0] = bCaseAbs = false; bBreak = true; } //## todo: this can be true iff the switch-expr type is an enum and all the constants are covered in the cases and they all have the same absolute non-break terminal (not an unusual use-case) } } bAbsolute[0] = bAbsolute[0] && bCaseAbs; } } } boolean bDefaultContributed = false; if( _defaultStatements != null && _defaultStatements.size() > 0 ) { if( !bBreak ) { // If none of the cases have a break, the cases all either fall through to the default clause // or never flow to the next stmt following this switch. Therefore, the default clause's terminal, // if one is present, establishes the switch's terminal. bAbsolute[0] = true; } boolean bDefaultAbs = false; for( int i = 0; i < _defaultStatements.size(); i++ ) { boolean[] bCsr = {false}; ITerminalStatement terminalStmt = _defaultStatements.get( i ).getLeastSignificantTerminalStatement( bCsr ); if( terminalStmt != null ) { if( !(terminalStmt instanceof IBreakStatement) ) { bDefaultAbs = bCsr[0]; termRet = getLeastSignificant( termRet, terminalStmt ); bDefaultContributed = true; } } } bAbsolute[0] = bAbsolute[0] && bDefaultAbs; } bAbsolute[0] = bAbsolute[0] && termRet != null && bDefaultContributed; return termRet; } @Override public String toString() { String strRet = "switch( " + getSwitchExpression().toString() + " )\n {\n"; if( _cases != null ) { for( int i = 0; i < _cases.length; i++ ) { strRet += "case " + _cases[i].getExpression().toString() + ":\n"; List caseStatements = _cases[i].getStatements(); if( caseStatements != null ) { for( int iStmt = 0; iStmt < caseStatements.size(); iStmt++ ) { strRet += (caseStatements.get( iStmt )).toString(); } } } if( _defaultStatements != null ) { strRet += "default:\n"; for( int iStmt = 0; iStmt < _defaultStatements.size(); iStmt++ ) { strRet += (_defaultStatements.get( iStmt )).toString(); } } } strRet += "\n}"; return strRet; } }