private static boolean hasDefaultClause(SwitchStatement node) { for (SwitchClause switchClause : node.getClauses()) { if (switchClause.isDefaultClause()) { return true; } } return false; }
private static boolean isStringSwitch(SwitchStatement node) { for (SwitchClause switchClause : node.getClauses()) { Expression expr = switchClause.getExpression(); if (expr != null && !(expr instanceof StringLiteral)) { return false; } } return true; }
private static boolean isCharSwitch(SwitchStatement node) { for (SwitchClause switchClause : node.getClauses()) { Expression expr = switchClause.getExpression(); if (expr != null) { if (expr instanceof StringLiteral && ((StringLiteral) expr).getValue().length() == 1) { continue; } return false; } } return true; }
static SwitchType of(SwitchStatement node) { List<SwitchClause> clauses = node.getClauses(); if (clauses.size() == 0 || clauses.size() == 1 && clauses.get(0).isDefaultClause()) { // empty or only default clause return Default; } if (isIntSwitch(node)) { return Int; } if (isCharSwitch(node)) { return Char; } if (isStringSwitch(node)) { return String; } return Generic; }
private static boolean isIntSwitch(SwitchStatement node) { for (SwitchClause switchClause : node.getClauses()) { Expression expr = switchClause.getExpression(); if (expr != null) { if (expr instanceof NumericLiteral && ((NumericLiteral) expr).isInt()) { continue; } if (expr instanceof UnaryExpression && ((UnaryExpression) expr).getOperator() == UnaryExpression.Operator.NEG && ((UnaryExpression) expr).getOperand() instanceof NumericLiteral && ((NumericLiteral) ((UnaryExpression) expr).getOperand()).isInt() && ((NumericLiteral) ((UnaryExpression) expr).getOperand()).intValue() != 0) { continue; } return false; } } return true; }
/** * 13.12.9 Runtime Semantics: CaseBlockEvaluation * * @param node the switch statement * @param type the switch statement type * @param lblExit the exit label * @param switchValue the variable which holds the switch value * @param mv the statement visitor * @return the completion value */ private Completion CaseBlockEvaluation( SwitchStatement node, SwitchType type, Jump lblExit, Variable<?> switchValue, StatementVisitor mv) { List<SwitchClause> clauses = node.getClauses(); Jump lblDefault = null; Jump[] labels = new Jump[clauses.size()]; for (int i = 0, size = clauses.size(); i < size; ++i) { labels[i] = new Jump(); if (clauses.get(i).isDefaultClause()) { assert lblDefault == null; lblDefault = labels[i]; } } if (type == SwitchType.Int) { emitIntSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv); } else if (type == SwitchType.Char) { emitCharSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv); } else if (type == SwitchType.String) { emitStringSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv); } else if (type == SwitchType.Generic) { emitGenericSwitch(clauses, labels, lblDefault, lblExit, switchValue, mv); } else { assert type == SwitchType.Default; assert switchValue == null; // Directly jump to default clause; since switch clauses before default clause are not // emitted, jump instruction can be elided as well, so we directly fall into the default // clause. } Completion result = Completion.Normal, lastResult = Completion.Normal; if (type == SwitchType.Default) { Iterator<SwitchClause> iter = clauses.iterator(); // skip leading clauses until default clause found while (iter.hasNext()) { SwitchClause switchClause = iter.next(); if (switchClause.isDefaultClause()) { lastResult = switchClause.accept(this, mv); break; } } // handle clauses following default clause until abrupt completion while (iter.hasNext() && !lastResult.isAbrupt()) { lastResult = iter.next().accept(this, mv); } result = lastResult; } else { int index = 0; for (SwitchClause switchClause : clauses) { Jump caseLabel = labels[index++]; if (caseLabel != null) { mv.mark(caseLabel); } else if (lastResult.isAbrupt()) { // Ignore unreachable targets continue; } Completion innerResult = switchClause.accept(this, mv); if (innerResult.isAbrupt()) { // not fall-thru result = result.isAbrupt() ? result.select(innerResult) : innerResult; } lastResult = innerResult; } } return result.normal(lblDefault == null || !lastResult.isAbrupt()); }