private void visitStatement()

in rhino/src/main/java/org/mozilla/javascript/CodeGenerator.java [275:553]


    private void visitStatement(Node node, int initialStackDepth) {
        int type = node.getType();
        Node child = node.getFirstChild();
        switch (type) {
            case Token.FUNCTION:
                {
                    int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
                    int fnType = scriptOrFn.getFunctionNode(fnIndex).getFunctionType();
                    // Only function expressions or function expression
                    // statements need closure code creating new function
                    // object on stack as function statements are initialized
                    // at script/function start.
                    // In addition, function expressions can not be present here
                    // at statement level, they must only be present as expressions.
                    if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
                        addIndexOp(Icode_CLOSURE_STMT, fnIndex);
                    } else {
                        if (fnType != FunctionNode.FUNCTION_STATEMENT) {
                            throw Kit.codeBug();
                        }
                    }
                    // For function statements or function expression statements
                    // in scripts, we need to ensure that the result of the script
                    // is the function if it is the last statement in the script.
                    // For example, eval("function () {}") should return a
                    // function, not undefined.
                    if (!itsInFunctionFlag) {
                        addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
                        stackChange(1);
                        addIcode(Icode_POP_RESULT);
                        stackChange(-1);
                    }
                }
                break;

            case Token.LABEL:
            case Token.LOOP:
            case Token.BLOCK:
            case Token.EMPTY:
            case Token.WITH:
                updateLineNumber(node);
            // fall through
            case Token.SCRIPT:
                while (child != null) {
                    visitStatement(child, initialStackDepth);
                    child = child.getNext();
                }
                break;

            case Token.ENTERWITH:
                visitExpression(child, 0);
                addToken(Token.ENTERWITH);
                stackChange(-1);
                break;

            case Token.LEAVEWITH:
                addToken(Token.LEAVEWITH);
                break;

            case Token.LOCAL_BLOCK:
                {
                    int local = allocLocal();
                    node.putIntProp(Node.LOCAL_PROP, local);
                    updateLineNumber(node);
                    while (child != null) {
                        visitStatement(child, initialStackDepth);
                        child = child.getNext();
                    }
                    addIndexOp(Icode_LOCAL_CLEAR, local);
                    releaseLocal(local);
                }
                break;

            case Token.DEBUGGER:
                addIcode(Icode_DEBUGGER);
                break;

            case Token.SWITCH:
                updateLineNumber(node);
                // See comments in IRFactory.createSwitch() for description
                // of SWITCH node
                {
                    visitExpression(child, 0);
                    for (Jump caseNode = (Jump) child.getNext();
                            caseNode != null;
                            caseNode = (Jump) caseNode.getNext()) {
                        if (caseNode.getType() != Token.CASE) throw badTree(caseNode);
                        Node test = caseNode.getFirstChild();
                        addIcode(Icode_DUP);
                        stackChange(1);
                        visitExpression(test, 0);
                        addToken(Token.SHEQ);
                        stackChange(-1);
                        // If true, Icode_IFEQ_POP will jump and remove case
                        // value from stack
                        addGoto(caseNode.target, Icode_IFEQ_POP);
                        stackChange(-1);
                    }
                    addIcode(Icode_POP);
                    stackChange(-1);
                }
                break;

            case Token.TARGET:
                markTargetLabel(node);
                break;

            case Token.IFEQ:
            case Token.IFNE:
                {
                    Node target = ((Jump) node).target;
                    visitExpression(child, 0);
                    addGoto(target, type);
                    stackChange(-1);
                }
                break;

            case Token.GOTO:
                {
                    Node target = ((Jump) node).target;
                    addGoto(target, type);
                }
                break;

            case Token.JSR:
                {
                    Node target = ((Jump) node).target;
                    addGoto(target, Icode_GOSUB);
                }
                break;

            case Token.FINALLY:
                {
                    // Account for incomming GOTOSUB address
                    stackChange(1);
                    int finallyRegister = getLocalBlockRef(node);
                    addIndexOp(Icode_STARTSUB, finallyRegister);
                    stackChange(-1);
                    while (child != null) {
                        visitStatement(child, initialStackDepth);
                        child = child.getNext();
                    }
                    addIndexOp(Icode_RETSUB, finallyRegister);
                }
                break;

            case Token.EXPR_VOID:
            case Token.EXPR_RESULT:
                updateLineNumber(node);
                visitExpression(child, 0);
                addIcode((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT);
                stackChange(-1);
                break;

            case Token.TRY:
                {
                    Jump tryNode = (Jump) node;
                    int exceptionObjectLocal = getLocalBlockRef(tryNode);
                    int scopeLocal = allocLocal();

                    addIndexOp(Icode_SCOPE_SAVE, scopeLocal);

                    int tryStart = iCodeTop;
                    boolean savedFlag = itsInTryFlag;
                    itsInTryFlag = true;
                    while (child != null) {
                        visitStatement(child, initialStackDepth);
                        child = child.getNext();
                    }
                    itsInTryFlag = savedFlag;

                    Node catchTarget = tryNode.target;
                    if (catchTarget != null) {
                        int catchStartPC = labelTable[getTargetLabel(catchTarget)];
                        addExceptionHandler(
                                tryStart,
                                catchStartPC,
                                catchStartPC,
                                false,
                                exceptionObjectLocal,
                                scopeLocal);
                    }
                    Node finallyTarget = tryNode.getFinally();
                    if (finallyTarget != null) {
                        int finallyStartPC = labelTable[getTargetLabel(finallyTarget)];
                        addExceptionHandler(
                                tryStart,
                                finallyStartPC,
                                finallyStartPC,
                                true,
                                exceptionObjectLocal,
                                scopeLocal);
                    }

                    addIndexOp(Icode_LOCAL_CLEAR, scopeLocal);
                    releaseLocal(scopeLocal);
                }
                break;

            case Token.CATCH_SCOPE:
                {
                    int localIndex = getLocalBlockRef(node);
                    int scopeIndex = node.getExistingIntProp(Node.CATCH_SCOPE_PROP);
                    String name = child.getType() == Token.NAME ? child.getString() : "";
                    child = child.getNext();
                    visitExpression(child, 0); // load expression object
                    addStringPrefix(name);
                    addIndexPrefix(localIndex);
                    addToken(Token.CATCH_SCOPE);
                    addUint8(scopeIndex != 0 ? 1 : 0);
                    stackChange(-1);
                }
                break;

            case Token.THROW:
                updateLineNumber(node);
                visitExpression(child, 0);
                addToken(Token.THROW);
                addUint16(lineNumber & 0xFFFF);
                stackChange(-1);
                break;

            case Token.RETHROW:
                updateLineNumber(node);
                addIndexOp(Token.RETHROW, getLocalBlockRef(node));
                break;

            case Token.RETURN:
                updateLineNumber(node);
                if (node.getIntProp(Node.GENERATOR_END_PROP, 0) != 0) {
                    if ((child == null)
                            || (compilerEnv.getLanguageVersion() < Context.VERSION_ES6)) {
                        // End generator function with no result, or old language version
                        // in which generators never return a result.
                        addIcode(Icode_GENERATOR_END);
                        addUint16(lineNumber & 0xFFFF);
                    } else {
                        visitExpression(child, ECF_TAIL);
                        addIcode(Icode_GENERATOR_RETURN);
                        addUint16(lineNumber & 0xFFFF);
                        stackChange(-1);
                    }

                } else {
                    if (child == null) {
                        addIcode(Icode_RETUNDEF);
                    } else {
                        visitExpression(child, ECF_TAIL);
                        addToken(Token.RETURN);
                        stackChange(-1);
                    }
                }
                break;

            case Token.RETURN_RESULT:
                updateLineNumber(node);
                addToken(Token.RETURN_RESULT);
                break;

            case Token.ENUM_INIT_KEYS:
            case Token.ENUM_INIT_VALUES:
            case Token.ENUM_INIT_ARRAY:
            case Token.ENUM_INIT_VALUES_IN_ORDER:
                visitExpression(child, 0);
                addIndexOp(type, getLocalBlockRef(node));
                stackChange(-1);
                break;

            case Icode_GENERATOR:
                break;

            default:
                throw badTree(node);
        }

        if (stackDepth != initialStackDepth) {
            throw Kit.codeBug();
        }
    }