Search in sources :

Example 16 with Jump

use of org.mozilla.javascript.ast.Jump in project HL4A by HL4A.

the class CodeGenerator method visitStatement.

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();
                // 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();
                    }
                }
                // 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);
        // fallthru
        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.getString();
                child = child.getNext();
                // load expression object
                visitExpression(child, 0);
                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) {
                // We're in a generator, so change RETURN to GENERATOR_END
                addIcode(Icode_GENERATOR_END);
                addUint16(lineNumber & 0xFFFF);
            } else if (child != null) {
                visitExpression(child, ECF_TAIL);
                addToken(Token.RETURN);
                stackChange(-1);
            } else {
                addIcode(Icode_RETUNDEF);
            }
            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();
    }
}
Also used : ScriptNode(org.mozilla.javascript.ast.ScriptNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode) Jump(org.mozilla.javascript.ast.Jump)

Example 17 with Jump

use of org.mozilla.javascript.ast.Jump in project HL4A by HL4A.

the class Node method toString.

private void toString(ObjToIntMap printIds, StringBuilder sb) {
    if (Token.printTrees) {
        sb.append(Token.name(type));
        if (this instanceof Name) {
            sb.append(' ');
            sb.append(getString());
            Scope scope = getScope();
            if (scope != null) {
                sb.append("[scope: ");
                appendPrintId(scope, printIds, sb);
                sb.append("]");
            }
        } else if (this instanceof Scope) {
            if (this instanceof ScriptNode) {
                ScriptNode sof = (ScriptNode) this;
                if (this instanceof FunctionNode) {
                    FunctionNode fn = (FunctionNode) this;
                    sb.append(' ');
                    sb.append(fn.getName());
                }
                sb.append(" [source name: ");
                sb.append(sof.getSourceName());
                sb.append("] [encoded source length: ");
                sb.append(sof.getEncodedSourceEnd() - sof.getEncodedSourceStart());
                sb.append("] [base line: ");
                sb.append(sof.getBaseLineno());
                sb.append("] [end line: ");
                sb.append(sof.getEndLineno());
                sb.append(']');
            }
            if (((Scope) this).getSymbolTable() != null) {
                sb.append(" [scope ");
                appendPrintId(this, printIds, sb);
                sb.append(": ");
                Iterator<String> iter = ((Scope) this).getSymbolTable().keySet().iterator();
                while (iter.hasNext()) {
                    sb.append(iter.next());
                    sb.append(" ");
                }
                sb.append("]");
            }
        } else if (this instanceof Jump) {
            Jump jump = (Jump) this;
            if (type == Token.BREAK || type == Token.CONTINUE) {
                sb.append(" [label: ");
                appendPrintId(jump.getJumpStatement(), printIds, sb);
                sb.append(']');
            } else if (type == Token.TRY) {
                Node catchNode = jump.target;
                Node finallyTarget = jump.getFinally();
                if (catchNode != null) {
                    sb.append(" [catch: ");
                    appendPrintId(catchNode, printIds, sb);
                    sb.append(']');
                }
                if (finallyTarget != null) {
                    sb.append(" [finally: ");
                    appendPrintId(finallyTarget, printIds, sb);
                    sb.append(']');
                }
            } else if (type == Token.LABEL || type == Token.LOOP || type == Token.SWITCH) {
                sb.append(" [break: ");
                appendPrintId(jump.target, printIds, sb);
                sb.append(']');
                if (type == Token.LOOP) {
                    sb.append(" [continue: ");
                    appendPrintId(jump.getContinue(), printIds, sb);
                    sb.append(']');
                }
            } else {
                sb.append(" [target: ");
                appendPrintId(jump.target, printIds, sb);
                sb.append(']');
            }
        } else if (type == Token.NUMBER) {
            sb.append(' ');
            sb.append(getDouble());
        } else if (type == Token.TARGET) {
            sb.append(' ');
            appendPrintId(this, printIds, sb);
        }
        if (lineno != -1) {
            sb.append(' ');
            sb.append(lineno);
        }
        for (PropListItem x = propListHead; x != null; x = x.next) {
            int type = x.type;
            sb.append(" [");
            sb.append(propToString(type));
            sb.append(": ");
            String value;
            switch(type) {
                case // can't add this as it recurses
                TARGETBLOCK_PROP:
                    value = "target block property";
                    break;
                case // can't add this as it is dull
                LOCAL_BLOCK_PROP:
                    value = "last local block";
                    break;
                case ISNUMBER_PROP:
                    switch(x.intValue) {
                        case BOTH:
                            value = "both";
                            break;
                        case RIGHT:
                            value = "right";
                            break;
                        case LEFT:
                            value = "left";
                            break;
                        default:
                            throw Kit.codeBug();
                    }
                    break;
                case SPECIALCALL_PROP:
                    switch(x.intValue) {
                        case SPECIALCALL_EVAL:
                            value = "eval";
                            break;
                        case SPECIALCALL_WITH:
                            value = "with";
                            break;
                        default:
                            // NON_SPECIALCALL should not be stored
                            throw Kit.codeBug();
                    }
                    break;
                case OBJECT_IDS_PROP:
                    {
                        Object[] a = (Object[]) x.objectValue;
                        value = "[";
                        for (int i = 0; i < a.length; i++) {
                            value += a[i].toString();
                            if (i + 1 < a.length)
                                value += ", ";
                        }
                        value += "]";
                        break;
                    }
                default:
                    Object obj = x.objectValue;
                    if (obj != null) {
                        value = obj.toString();
                    } else {
                        value = String.valueOf(x.intValue);
                    }
                    break;
            }
            sb.append(value);
            sb.append(']');
        }
    }
}
Also used : Scope(org.mozilla.javascript.ast.Scope) ScriptNode(org.mozilla.javascript.ast.ScriptNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode) Iterator(java.util.Iterator) ScriptNode(org.mozilla.javascript.ast.ScriptNode) Jump(org.mozilla.javascript.ast.Jump) Name(org.mozilla.javascript.ast.Name)

Example 18 with Jump

use of org.mozilla.javascript.ast.Jump in project HL4A by HL4A.

the class NodeTransformer method transformCompilationUnit_r.

private void transformCompilationUnit_r(final ScriptNode tree, final Node parent, Scope scope, boolean createScopeObjects, boolean inStrictMode) {
    Node node = null;
    siblingLoop: for (; ; ) {
        Node previous = null;
        if (node == null) {
            node = parent.getFirstChild();
        } else {
            previous = node;
            node = node.getNext();
        }
        if (node == null) {
            break;
        }
        int type = node.getType();
        if (createScopeObjects && (type == Token.BLOCK || type == Token.LOOP || type == Token.ARRAYCOMP) && (node instanceof Scope)) {
            Scope newScope = (Scope) node;
            if (newScope.getSymbolTable() != null) {
                // transform to let statement so we get a with statement
                // created to contain scoped let variables
                Node let = new Node(type == Token.ARRAYCOMP ? Token.LETEXPR : Token.LET);
                Node innerLet = new Node(Token.LET);
                let.addChildToBack(innerLet);
                for (String name : newScope.getSymbolTable().keySet()) {
                    innerLet.addChildToBack(Node.newString(Token.NAME, name));
                }
                // so we don't transform again
                newScope.setSymbolTable(null);
                Node oldNode = node;
                node = replaceCurrent(parent, previous, node, let);
                type = node.getType();
                let.addChildToBack(oldNode);
            }
        }
        switch(type) {
            case Token.LABEL:
            case Token.SWITCH:
            case Token.LOOP:
                loops.push(node);
                loopEnds.push(((Jump) node).target);
                break;
            case Token.WITH:
                {
                    loops.push(node);
                    Node leave = node.getNext();
                    if (leave.getType() != Token.LEAVEWITH) {
                        Kit.codeBug();
                    }
                    loopEnds.push(leave);
                    break;
                }
            case Token.TRY:
                {
                    Jump jump = (Jump) node;
                    Node finallytarget = jump.getFinally();
                    if (finallytarget != null) {
                        hasFinally = true;
                        loops.push(node);
                        loopEnds.push(finallytarget);
                    }
                    break;
                }
            case Token.TARGET:
            case Token.LEAVEWITH:
                if (!loopEnds.isEmpty() && loopEnds.peek() == node) {
                    loopEnds.pop();
                    loops.pop();
                }
                break;
            case Token.YIELD:
                ((FunctionNode) tree).addResumptionPoint(node);
                break;
            case Token.RETURN:
                {
                    boolean isGenerator = tree.getType() == Token.FUNCTION && ((FunctionNode) tree).isGenerator();
                    if (isGenerator) {
                        node.putIntProp(Node.GENERATOR_END_PROP, 1);
                    }
                    /* If we didn't support try/finally, it wouldn't be
                 * necessary to put LEAVEWITH nodes here... but as
                 * we do need a series of JSR FINALLY nodes before
                 * each RETURN, we need to ensure that each finally
                 * block gets the correct scope... which could mean
                 * that some LEAVEWITH nodes are necessary.
                 */
                    if (!hasFinally)
                        // skip the whole mess.
                        break;
                    Node unwindBlock = null;
                    for (int i = loops.size() - 1; i >= 0; i--) {
                        Node n = (Node) loops.get(i);
                        int elemtype = n.getType();
                        if (elemtype == Token.TRY || elemtype == Token.WITH) {
                            Node unwind;
                            if (elemtype == Token.TRY) {
                                Jump jsrnode = new Jump(Token.JSR);
                                Node jsrtarget = ((Jump) n).getFinally();
                                jsrnode.target = jsrtarget;
                                unwind = jsrnode;
                            } else {
                                unwind = new Node(Token.LEAVEWITH);
                            }
                            if (unwindBlock == null) {
                                unwindBlock = new Node(Token.BLOCK, node.getLineno());
                            }
                            unwindBlock.addChildToBack(unwind);
                        }
                    }
                    if (unwindBlock != null) {
                        Node returnNode = node;
                        Node returnExpr = returnNode.getFirstChild();
                        node = replaceCurrent(parent, previous, node, unwindBlock);
                        if (returnExpr == null || isGenerator) {
                            unwindBlock.addChildToBack(returnNode);
                        } else {
                            Node store = new Node(Token.EXPR_RESULT, returnExpr);
                            unwindBlock.addChildToFront(store);
                            returnNode = new Node(Token.RETURN_RESULT);
                            unwindBlock.addChildToBack(returnNode);
                            // transform return expression
                            transformCompilationUnit_r(tree, store, scope, createScopeObjects, inStrictMode);
                        }
                        // skip transformCompilationUnit_r to avoid infinite loop
                        continue siblingLoop;
                    }
                    break;
                }
            case Token.BREAK:
            case Token.CONTINUE:
                {
                    Jump jump = (Jump) node;
                    Jump jumpStatement = jump.getJumpStatement();
                    if (jumpStatement == null)
                        Kit.codeBug();
                    for (int i = loops.size(); ; ) {
                        if (i == 0) {
                            // which should be found
                            throw Kit.codeBug();
                        }
                        --i;
                        Node n = (Node) loops.get(i);
                        if (n == jumpStatement) {
                            break;
                        }
                        int elemtype = n.getType();
                        if (elemtype == Token.WITH) {
                            Node leave = new Node(Token.LEAVEWITH);
                            previous = addBeforeCurrent(parent, previous, node, leave);
                        } else if (elemtype == Token.TRY) {
                            Jump tryNode = (Jump) n;
                            Jump jsrFinally = new Jump(Token.JSR);
                            jsrFinally.target = tryNode.getFinally();
                            previous = addBeforeCurrent(parent, previous, node, jsrFinally);
                        }
                    }
                    if (type == Token.BREAK) {
                        jump.target = jumpStatement.target;
                    } else {
                        jump.target = jumpStatement.getContinue();
                    }
                    jump.setType(Token.GOTO);
                    break;
                }
            case Token.CALL:
                visitCall(node, tree);
                break;
            case Token.NEW:
                visitNew(node, tree);
                break;
            case Token.LETEXPR:
            case Token.LET:
                {
                    Node child = node.getFirstChild();
                    if (child.getType() == Token.LET) {
                        // We have a let statement or expression rather than a
                        // let declaration
                        boolean createWith = tree.getType() != Token.FUNCTION || ((FunctionNode) tree).requiresActivation();
                        node = visitLet(createWith, parent, previous, node);
                        break;
                    } else {
                    // fall through to process let declaration...
                    }
                }
            /* fall through */
            case Token.CONST:
            case Token.VAR:
                {
                    Node result = new Node(Token.BLOCK);
                    for (Node cursor = node.getFirstChild(); cursor != null; ) {
                        // Move cursor to next before createAssignment gets chance
                        // to change n.next
                        Node n = cursor;
                        cursor = cursor.getNext();
                        if (n.getType() == Token.NAME) {
                            if (!n.hasChildren())
                                continue;
                            Node init = n.getFirstChild();
                            n.removeChild(init);
                            n.setType(Token.BINDNAME);
                            n = new Node(type == Token.CONST ? Token.SETCONST : Token.SETNAME, n, init);
                        } else {
                            // to a LETEXPR
                            if (n.getType() != Token.LETEXPR)
                                throw Kit.codeBug();
                        }
                        Node pop = new Node(Token.EXPR_VOID, n, node.getLineno());
                        result.addChildToBack(pop);
                    }
                    node = replaceCurrent(parent, previous, node, result);
                    break;
                }
            case Token.TYPEOFNAME:
                {
                    Scope defining = scope.getDefiningScope(node.getString());
                    if (defining != null) {
                        node.setScope(defining);
                    }
                }
                break;
            case Token.TYPEOF:
            case Token.IFNE:
                {
                    /* We want to suppress warnings for undefined property o.p
                   * for the following constructs: typeof o.p, if (o.p),
                   * if (!o.p), if (o.p == undefined), if (undefined == o.p)
                   */
                    Node child = node.getFirstChild();
                    if (type == Token.IFNE) {
                        while (child.getType() == Token.NOT) {
                            child = child.getFirstChild();
                        }
                        if (child.getType() == Token.EQ || child.getType() == Token.NE) {
                            Node first = child.getFirstChild();
                            Node last = child.getLastChild();
                            if (first.getType() == Token.NAME && first.getString().equals("undefined")) {
                                child = last;
                            } else if (last.getType() == Token.NAME && last.getString().equals("undefined")) {
                                child = first;
                            }
                        }
                    }
                    if (child.getType() == Token.GETPROP) {
                        child.setType(Token.GETPROPNOWARN);
                    }
                    break;
                }
            case Token.SETNAME:
                if (inStrictMode) {
                    node.setType(Token.STRICT_SETNAME);
                }
            /* fall through */
            case Token.NAME:
            case Token.SETCONST:
            case Token.DELPROP:
                {
                    // Turn name to var for faster access if possible
                    if (createScopeObjects) {
                        break;
                    }
                    Node nameSource;
                    if (type == Token.NAME) {
                        nameSource = node;
                    } else {
                        nameSource = node.getFirstChild();
                        if (nameSource.getType() != Token.BINDNAME) {
                            if (type == Token.DELPROP) {
                                break;
                            }
                            throw Kit.codeBug();
                        }
                    }
                    if (nameSource.getScope() != null) {
                        // already have a scope set
                        break;
                    }
                    String name = nameSource.getString();
                    Scope defining = scope.getDefiningScope(name);
                    if (defining != null) {
                        nameSource.setScope(defining);
                        if (type == Token.NAME) {
                            node.setType(Token.GETVAR);
                        } else if (type == Token.SETNAME || type == Token.STRICT_SETNAME) {
                            node.setType(Token.SETVAR);
                            nameSource.setType(Token.STRING);
                        } else if (type == Token.SETCONST) {
                            node.setType(Token.SETCONSTVAR);
                            nameSource.setType(Token.STRING);
                        } else if (type == Token.DELPROP) {
                            // Local variables are by definition permanent
                            Node n = new Node(Token.FALSE);
                            node = replaceCurrent(parent, previous, node, n);
                        } else {
                            throw Kit.codeBug();
                        }
                    }
                    break;
                }
        }
        transformCompilationUnit_r(tree, node, node instanceof Scope ? (Scope) node : scope, createScopeObjects, inStrictMode);
    }
}
Also used : Scope(org.mozilla.javascript.ast.Scope) ScriptNode(org.mozilla.javascript.ast.ScriptNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode) Jump(org.mozilla.javascript.ast.Jump)

Aggregations

Jump (org.mozilla.javascript.ast.Jump)18 FunctionNode (org.mozilla.javascript.ast.FunctionNode)16 ScriptNode (org.mozilla.javascript.ast.ScriptNode)16 AstNode (org.mozilla.javascript.ast.AstNode)6 LetNode (org.mozilla.javascript.ast.LetNode)6 Scope (org.mozilla.javascript.ast.Scope)4 Name (org.mozilla.javascript.ast.Name)3 Iterator (java.util.Iterator)2 ArrayLiteral (org.mozilla.javascript.ast.ArrayLiteral)1 BreakStatement (org.mozilla.javascript.ast.BreakStatement)1 LabeledStatement (org.mozilla.javascript.ast.LabeledStatement)1