private void print(SwitchStatement node) throws IOException { writer.append("switch").ws().append('('); print(node.getExpression()); writer.append(')').ws().append('{').indent().softNewLine(); for (SwitchCase sc : node.getCases()) { if (sc.getExpression() == null) { writer.append("default:"); } else { writer.append("case "); print(sc.getExpression()); writer.append(':'); } writer.indent().softNewLine(); if (sc.getStatements() != null) { for (AstNode stmt : sc.getStatements()) { print(stmt); writer.softNewLine(); } } writer.outdent(); } writer.append('}'); }
private void processCaseNode(Node child, CodeBlock block, Set<Completion> set, String entered, int offset) { SwitchCase switchCase = (SwitchCase) child; List<AstNode> statements = switchCase.getStatements(); int start = switchCase.getAbsolutePosition(); offset = start + switchCase.getLength(); if (canProcessNode(switchCase)) { block = block.addChildCodeBlock(start); block.setEndOffset(offset); if(statements != null) { for (AstNode node : statements) { iterateNode(node, set, entered, block, offset); } } } }
/** * generate constraints for a switch-statement */ private void processSwitchCase(SwitchCase sc) { SwitchStatement ss = (SwitchStatement)sc.getParent(); if (sc.getExpression() != null){ // default case has no expression ITypeTerm switchExpTerm = findOrCreateExpressionTerm(ss.getExpression()); ITypeTerm switchCaseTerm = processExpression(sc.getExpression()); addTypeEqualityConstraint(switchExpTerm, switchCaseTerm, sc.getLineno(), (solution) -> genericTypeError("switch expression must have the same type as its cases", locationOf(sc))); } }
/** Extract local variables from switch node* */ private void processSwitchNode(Node child, CodeBlock block, Set<Completion> set, String entered, int offset) { SwitchStatement switchStatement = (SwitchStatement) child; if (canProcessNode(switchStatement)) { List<SwitchCase> cases = switchStatement.getCases(); if(cases != null) { for (SwitchCase switchCase : cases) { iterateNode(switchCase, set, entered, block, offset); } } } }
private Node transformSwitch(SwitchStatement node) { // The switch will be rewritten from: // // switch (expr) { // case test1: statements1; // ... // default: statementsDefault; // ... // case testN: statementsN; // } // // to: // // { // switch (expr) { // case test1: goto label1; // ... // case testN: goto labelN; // } // goto labelDefault; // label1: // statements1; // ... // labelDefault: // statementsDefault; // ... // labelN: // statementsN; // breakLabel: // } // // where inside switch each "break;" without label will be replaced // by "goto breakLabel". // // If the original switch does not have the default label, then // after the switch he transformed code would contain this goto: // goto breakLabel; // instead of: // goto labelDefault; decompiler.addToken(Token.SWITCH); decompiler.addToken(Token.LP); Node switchExpr = transform(node.getExpression()); decompiler.addToken(Token.RP); node.addChildToBack(switchExpr); Node block = new Node(Token.BLOCK, node, node.getLineno()); decompiler.addEOL(Token.LC); for (SwitchCase sc : node.getCases()) { AstNode expr = sc.getExpression(); Node caseExpr = null; if (expr != null) { decompiler.addToken(Token.CASE); caseExpr = transform(expr); } else { decompiler.addToken(Token.DEFAULT); } decompiler.addEOL(Token.COLON); List<AstNode> stmts = sc.getStatements(); Node body = new Block(); if (stmts != null) { for (AstNode kid : stmts) { body.addChildToBack(transform(kid)); } } addSwitchCase(block, caseExpr, body); } decompiler.addEOL(Token.RC); closeSwitch(block); return block; }
private SwitchStatement switchStatement() throws IOException { if (currentToken != Token.SWITCH) codeBug(); consumeToken(); int pos = ts.tokenBeg; SwitchStatement pn = new SwitchStatement(pos); if (mustMatchToken(Token.LP, "msg.no.paren.switch")) pn.setLp(ts.tokenBeg - pos); pn.setLineno(ts.lineno); AstNode discriminant = expr(); pn.setExpression(discriminant); enterSwitch(pn); try { if (mustMatchToken(Token.RP, "msg.no.paren.after.switch")) pn.setRp(ts.tokenBeg - pos); mustMatchToken(Token.LC, "msg.no.brace.switch"); boolean hasDefault = false; int tt; switchLoop: for (;;) { tt = nextToken(); int casePos = ts.tokenBeg; int caseLineno = ts.lineno; AstNode caseExpression = null; switch (tt) { case Token.RC: pn.setLength(ts.tokenEnd - pos); break switchLoop; case Token.CASE: caseExpression = expr(); mustMatchToken(Token.COLON, "msg.no.colon.case"); break; case Token.DEFAULT: if (hasDefault) { reportError("msg.double.switch.default"); } hasDefault = true; caseExpression = null; mustMatchToken(Token.COLON, "msg.no.colon.case"); break; default: reportError("msg.bad.switch"); break switchLoop; } SwitchCase caseNode = new SwitchCase(casePos); caseNode.setExpression(caseExpression); caseNode.setLength(ts.tokenEnd - pos); // include colon caseNode.setLineno(caseLineno); while ((tt = peekToken()) != Token.RC && tt != Token.CASE && tt != Token.DEFAULT && tt != Token.EOF) { caseNode.addStatement(statement()); // updates length } pn.addCase(caseNode); } } finally { exitSwitch(); } return pn; }
/** * This method generates constraints for all relevant AstNodes. It delegates its work to various * processXXX() methods that handle AstNodes of type XXX. */ @Override public boolean visit(AstNode node) { if (node instanceof VariableInitializer){ processVariableInitializer(node); } else if (node instanceof ReturnStatement){ processReturnStatement((ReturnStatement)node); } else if (node instanceof ExpressionStatement){ processExpressionStatement((ExpressionStatement)node); } else if (node instanceof ForLoop){ processForLoop((ForLoop)node); } else if (node instanceof ForInLoop){ processForInLoop((ForInLoop)node); }else if (node instanceof WhileLoop){ processWhileLoop((WhileLoop)node); } else if (node instanceof DoLoop){ processDoLoop((DoLoop)node); } else if (node instanceof NewExpression){ processNewExpression((NewExpression)node); } else if (node instanceof FunctionCall){ processFunctionCall((FunctionCall)node); } else if (node instanceof ElementGet){ processElementGet((ElementGet)node); } else if (node instanceof FunctionNode){ processFunctionNode((FunctionNode)node); } else if (node instanceof IfStatement){ processIfStatement((IfStatement)node); } else if (node instanceof KeywordLiteral){ processKeywordLiteral((KeywordLiteral)node); } else if (node instanceof SwitchStatement){ processSwitchStatement((SwitchStatement)node); } else if (node instanceof SwitchCase){ processSwitchCase((SwitchCase)node); } else if ((node instanceof AstRoot) || //AstRoot: no constraints need to be generated (node instanceof BreakStatement) || //BreakStatement: no constraints need to be generated (node instanceof VariableDeclaration) || //VariableDeclaration: we generate constraints for its constituent VariableInitializer nodes (node instanceof Name) || //Name: generate constraints for complex expressions that refer to names (node instanceof NumberLiteral) || //NumberLiteral: generate constraints for complex expressions that refer to names (node instanceof StringLiteral) || //StringLiteral: generate constraints for complex expressions that refer to names (node instanceof Assignment) || // Assignment is a special case of InfixExpression (node instanceof ArrayLiteral) || (node instanceof UnaryExpression) || (node instanceof InfixExpression) || (node instanceof ConditionalExpression) || (node instanceof ParenthesizedExpression) || (node instanceof EmptyExpression) || (node instanceof ObjectLiteral) || (node instanceof EmptyStatement) || (node instanceof ContinueStatement) || (node instanceof Scope) || (node instanceof Block)){ // // occurs in programs with for loops -- nothing to be done here? /* nothing */ } else { error("unsupported node " + node.toSource().trim() + " of type: " + node.getClass().getName(), node); } return true; }