Search in sources :

Example 16 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

the class CodeGenerator method visitExpression.

private void visitExpression(Node node, int contextFlags) {
    int type = node.getType();
    Node child = node.getFirstChild();
    int savedStackDepth = stackDepth;
    switch(type) {
        case Token.FUNCTION:
            {
                int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
                FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
                // See comments in visitStatement for Token.FUNCTION case
                if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION) {
                    throw Kit.codeBug();
                }
                addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
                stackChange(1);
            }
            break;
        case Token.LOCAL_LOAD:
            {
                int localIndex = getLocalBlockRef(node);
                addIndexOp(Token.LOCAL_LOAD, localIndex);
                stackChange(1);
            }
            break;
        case Token.COMMA:
            {
                Node lastChild = node.getLastChild();
                while (child != lastChild) {
                    visitExpression(child, 0);
                    addIcode(Icode_POP);
                    stackChange(-1);
                    child = child.getNext();
                }
                // Preserve tail context flag if any
                visitExpression(child, contextFlags & ECF_TAIL);
            }
            break;
        case Token.USE_STACK:
            // Indicates that stack was modified externally,
            // like placed catch object
            stackChange(1);
            break;
        case Token.REF_CALL:
        case Token.CALL:
        case Token.NEW:
            {
                if (type == Token.NEW) {
                    visitExpression(child, 0);
                } else {
                    generateCallFunAndThis(child);
                }
                int argCount = 0;
                while ((child = child.getNext()) != null) {
                    visitExpression(child, 0);
                    ++argCount;
                }
                int callType = node.getIntProp(Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL);
                if (callType != Node.NON_SPECIALCALL) {
                    // embed line number and source filename
                    addIndexOp(Icode_CALLSPECIAL, argCount);
                    addUint8(callType);
                    addUint8(type == Token.NEW ? 1 : 0);
                    addUint16(lineNumber & 0xFFFF);
                } else {
                    // optimization will confuse the debugger)
                    if (type == Token.CALL && (contextFlags & ECF_TAIL) != 0 && !compilerEnv.isGenerateDebugInfo() && !itsInTryFlag) {
                        type = Icode_TAIL_CALL;
                    }
                    addIndexOp(type, argCount);
                }
                // adjust stack
                if (type == Token.NEW) {
                    // new: f, args -> result
                    stackChange(-argCount);
                } else {
                    // call: f, thisObj, args -> result
                    // ref_call: f, thisObj, args -> ref
                    stackChange(-1 - argCount);
                }
                if (argCount > itsData.itsMaxCalleeArgs) {
                    itsData.itsMaxCalleeArgs = argCount;
                }
            }
            break;
        case Token.AND:
        case Token.OR:
            {
                visitExpression(child, 0);
                addIcode(Icode_DUP);
                stackChange(1);
                int afterSecondJumpStart = iCodeTop;
                int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
                addGotoOp(jump);
                stackChange(-1);
                addIcode(Icode_POP);
                stackChange(-1);
                child = child.getNext();
                // Preserve tail context flag if any
                visitExpression(child, contextFlags & ECF_TAIL);
                resolveForwardGoto(afterSecondJumpStart);
            }
            break;
        case Token.HOOK:
            {
                Node ifThen = child.getNext();
                Node ifElse = ifThen.getNext();
                visitExpression(child, 0);
                int elseJumpStart = iCodeTop;
                addGotoOp(Token.IFNE);
                stackChange(-1);
                // Preserve tail context flag if any
                visitExpression(ifThen, contextFlags & ECF_TAIL);
                int afterElseJumpStart = iCodeTop;
                addGotoOp(Token.GOTO);
                resolveForwardGoto(elseJumpStart);
                stackDepth = savedStackDepth;
                // Preserve tail context flag if any
                visitExpression(ifElse, contextFlags & ECF_TAIL);
                resolveForwardGoto(afterElseJumpStart);
            }
            break;
        case Token.GETPROP:
        case Token.GETPROPNOWARN:
            visitExpression(child, 0);
            child = child.getNext();
            addStringOp(type, child.getString());
            break;
        case Token.GETELEM:
        case Token.DELPROP:
        case Token.BITAND:
        case Token.BITOR:
        case Token.BITXOR:
        case Token.LSH:
        case Token.RSH:
        case Token.URSH:
        case Token.ADD:
        case Token.SUB:
        case Token.MOD:
        case Token.DIV:
        case Token.MUL:
        case Token.EQ:
        case Token.NE:
        case Token.SHEQ:
        case Token.SHNE:
        case Token.IN:
        case Token.INSTANCEOF:
        case Token.LE:
        case Token.LT:
        case Token.GE:
        case Token.GT:
            visitExpression(child, 0);
            child = child.getNext();
            visitExpression(child, 0);
            addToken(type);
            stackChange(-1);
            break;
        case Token.POS:
        case Token.NEG:
        case Token.NOT:
        case Token.BITNOT:
        case Token.TYPEOF:
        case Token.VOID:
            visitExpression(child, 0);
            if (type == Token.VOID) {
                addIcode(Icode_POP);
                addIcode(Icode_UNDEF);
            } else {
                addToken(type);
            }
            break;
        case Token.GET_REF:
        case Token.DEL_REF:
            visitExpression(child, 0);
            addToken(type);
            break;
        case Token.SETPROP:
        case Token.SETPROP_OP:
            {
                visitExpression(child, 0);
                child = child.getNext();
                String property = child.getString();
                child = child.getNext();
                if (type == Token.SETPROP_OP) {
                    addIcode(Icode_DUP);
                    stackChange(1);
                    addStringOp(Token.GETPROP, property);
                    // Compensate for the following USE_STACK
                    stackChange(-1);
                }
                visitExpression(child, 0);
                addStringOp(Token.SETPROP, property);
                stackChange(-1);
            }
            break;
        case Token.SETELEM:
        case Token.SETELEM_OP:
            visitExpression(child, 0);
            child = child.getNext();
            visitExpression(child, 0);
            child = child.getNext();
            if (type == Token.SETELEM_OP) {
                addIcode(Icode_DUP2);
                stackChange(2);
                addToken(Token.GETELEM);
                stackChange(-1);
                // Compensate for the following USE_STACK
                stackChange(-1);
            }
            visitExpression(child, 0);
            addToken(Token.SETELEM);
            stackChange(-2);
            break;
        case Token.SET_REF:
        case Token.SET_REF_OP:
            visitExpression(child, 0);
            child = child.getNext();
            if (type == Token.SET_REF_OP) {
                addIcode(Icode_DUP);
                stackChange(1);
                addToken(Token.GET_REF);
                // Compensate for the following USE_STACK
                stackChange(-1);
            }
            visitExpression(child, 0);
            addToken(Token.SET_REF);
            stackChange(-1);
            break;
        case Token.STRICT_SETNAME:
        case Token.SETNAME:
            {
                String name = child.getString();
                visitExpression(child, 0);
                child = child.getNext();
                visitExpression(child, 0);
                addStringOp(type, name);
                stackChange(-1);
            }
            break;
        case Token.SETCONST:
            {
                String name = child.getString();
                visitExpression(child, 0);
                child = child.getNext();
                visitExpression(child, 0);
                addStringOp(Icode_SETCONST, name);
                stackChange(-1);
            }
            break;
        case Token.TYPEOFNAME:
            {
                int index = -1;
                // since the vars all exist there instead of in jregs
                if (itsInFunctionFlag && !itsData.itsNeedsActivation)
                    index = scriptOrFn.getIndexForNameNode(node);
                if (index == -1) {
                    addStringOp(Icode_TYPEOFNAME, node.getString());
                    stackChange(1);
                } else {
                    addVarOp(Token.GETVAR, index);
                    stackChange(1);
                    addToken(Token.TYPEOF);
                }
            }
            break;
        case Token.BINDNAME:
        case Token.NAME:
        case Token.STRING:
            addStringOp(type, node.getString());
            stackChange(1);
            break;
        case Token.INC:
        case Token.DEC:
            visitIncDec(node, child);
            break;
        case Token.NUMBER:
            {
                double num = node.getDouble();
                int inum = (int) num;
                if (inum == num) {
                    if (inum == 0) {
                        addIcode(Icode_ZERO);
                        // Check for negative zero
                        if (1.0 / num < 0.0) {
                            addToken(Token.NEG);
                        }
                    } else if (inum == 1) {
                        addIcode(Icode_ONE);
                    } else if ((short) inum == inum) {
                        addIcode(Icode_SHORTNUMBER);
                        // write short as uin16 bit pattern
                        addUint16(inum & 0xFFFF);
                    } else {
                        addIcode(Icode_INTNUMBER);
                        addInt(inum);
                    }
                } else {
                    int index = getDoubleIndex(num);
                    addIndexOp(Token.NUMBER, index);
                }
                stackChange(1);
            }
            break;
        case Token.GETVAR:
            {
                if (itsData.itsNeedsActivation)
                    Kit.codeBug();
                int index = scriptOrFn.getIndexForNameNode(node);
                addVarOp(Token.GETVAR, index);
                stackChange(1);
            }
            break;
        case Token.SETVAR:
            {
                if (itsData.itsNeedsActivation)
                    Kit.codeBug();
                int index = scriptOrFn.getIndexForNameNode(child);
                child = child.getNext();
                visitExpression(child, 0);
                addVarOp(Token.SETVAR, index);
            }
            break;
        case Token.SETCONSTVAR:
            {
                if (itsData.itsNeedsActivation)
                    Kit.codeBug();
                int index = scriptOrFn.getIndexForNameNode(child);
                child = child.getNext();
                visitExpression(child, 0);
                addVarOp(Token.SETCONSTVAR, index);
            }
            break;
        case Token.NULL:
        case Token.THIS:
        case Token.THISFN:
        case Token.FALSE:
        case Token.TRUE:
            addToken(type);
            stackChange(1);
            break;
        case Token.ENUM_NEXT:
        case Token.ENUM_ID:
            addIndexOp(type, getLocalBlockRef(node));
            stackChange(1);
            break;
        case Token.REGEXP:
            {
                int index = node.getExistingIntProp(Node.REGEXP_PROP);
                addIndexOp(Token.REGEXP, index);
                stackChange(1);
            }
            break;
        case Token.ARRAYLIT:
        case Token.OBJECTLIT:
            visitLiteral(node, child);
            break;
        case Token.ARRAYCOMP:
            visitArrayComprehension(node, child, child.getNext());
            break;
        case Token.REF_SPECIAL:
            visitExpression(child, 0);
            addStringOp(type, (String) node.getProp(Node.NAME_PROP));
            break;
        case Token.REF_MEMBER:
        case Token.REF_NS_MEMBER:
        case Token.REF_NAME:
        case Token.REF_NS_NAME:
            {
                int memberTypeFlags = node.getIntProp(Node.MEMBER_TYPE_PROP, 0);
                // generate possible target, possible namespace and member
                int childCount = 0;
                do {
                    visitExpression(child, 0);
                    ++childCount;
                    child = child.getNext();
                } while (child != null);
                addIndexOp(type, memberTypeFlags);
                stackChange(1 - childCount);
            }
            break;
        case Token.DOTQUERY:
            {
                int queryPC;
                updateLineNumber(node);
                visitExpression(child, 0);
                addIcode(Icode_ENTERDQ);
                stackChange(-1);
                queryPC = iCodeTop;
                visitExpression(child.getNext(), 0);
                addBackwardGoto(Icode_LEAVEDQ, queryPC);
            }
            break;
        case Token.DEFAULTNAMESPACE:
        case Token.ESCXMLATTR:
        case Token.ESCXMLTEXT:
            visitExpression(child, 0);
            addToken(type);
            break;
        case Token.YIELD:
            if (child != null) {
                visitExpression(child, 0);
            } else {
                addIcode(Icode_UNDEF);
                stackChange(1);
            }
            addToken(Token.YIELD);
            addUint16(node.getLineno() & 0xFFFF);
            break;
        case Token.WITHEXPR:
            {
                Node enterWith = node.getFirstChild();
                Node with = enterWith.getNext();
                visitExpression(enterWith.getFirstChild(), 0);
                addToken(Token.ENTERWITH);
                stackChange(-1);
                visitExpression(with.getFirstChild(), 0);
                addToken(Token.LEAVEWITH);
                break;
            }
        default:
            throw badTree(node);
    }
    if (savedStackDepth + 1 != stackDepth) {
        Kit.codeBug();
    }
}
Also used : ScriptNode(org.mozilla.javascript.ast.ScriptNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode)

Example 17 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

the class CodeGenerator method generateFunctionICode.

private void generateFunctionICode() {
    itsInFunctionFlag = true;
    FunctionNode theFunction = (FunctionNode) scriptOrFn;
    itsData.itsFunctionType = theFunction.getFunctionType();
    itsData.itsNeedsActivation = theFunction.requiresActivation();
    if (theFunction.getFunctionName() != null) {
        itsData.itsName = theFunction.getName();
    }
    if (!theFunction.getIgnoreDynamicScope()) {
        if (compilerEnv.isUseDynamicScope()) {
            itsData.useDynamicScope = true;
        }
    }
    if (theFunction.isGenerator()) {
        addIcode(Icode_GENERATOR);
        addUint16(theFunction.getBaseLineno() & 0xFFFF);
    }
    generateICodeFromTree(theFunction.getLastChild());
}
Also used : FunctionNode(org.mozilla.javascript.ast.FunctionNode)

Example 18 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

the class Node method toString.

private void toString(ObjToIntMap printIds, StringBuffer 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 19 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

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)

Example 20 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

the class NodeTransformer method transform.

public final void transform(ScriptNode tree) {
    transformCompilationUnit(tree);
    for (int i = 0; i != tree.getFunctionCount(); ++i) {
        FunctionNode fn = tree.getFunctionNode(i);
        transform(fn);
    }
}
Also used : FunctionNode(org.mozilla.javascript.ast.FunctionNode)

Aggregations

FunctionNode (org.mozilla.javascript.ast.FunctionNode)32 ScriptNode (org.mozilla.javascript.ast.ScriptNode)20 AstNode (org.mozilla.javascript.ast.AstNode)8 Name (org.mozilla.javascript.ast.Name)7 LetNode (org.mozilla.javascript.ast.LetNode)6 Jump (org.mozilla.javascript.ast.Jump)4 Scope (org.mozilla.javascript.ast.Scope)4 XmlString (org.mozilla.javascript.ast.XmlString)3 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 Iterator (java.util.Iterator)2 Map (java.util.Map)2 AstRoot (org.mozilla.javascript.ast.AstRoot)2 ErrorNode (org.mozilla.javascript.ast.ErrorNode)2 Block (org.mozilla.javascript.ast.Block)1 Comment (org.mozilla.javascript.ast.Comment)1 EmptyExpression (org.mozilla.javascript.ast.EmptyExpression)1 ExpressionStatement (org.mozilla.javascript.ast.ExpressionStatement)1 ObjectProperty (org.mozilla.javascript.ast.ObjectProperty)1 ParenthesizedExpression (org.mozilla.javascript.ast.ParenthesizedExpression)1