public JsFunction mapFunction(Node fnNode) throws JsParserException { int nodeType = fnNode.getType(); assert nodeType == TokenStream.FUNCTION : "Expected function node, got: " + TokenStream.tokenToName(nodeType); Node fromFnNameNode = fnNode.getFirstChild(); Node fromParamNode = fnNode.getFirstChild().getNext().getFirstChild(); Node fromBodyNode = fnNode.getFirstChild().getNext().getNext(); JsFunction toFn = scopeContext.enterFunction(); // Decide the function's name, if any. // String fnNameIdent = fromFnNameNode.getString(); if (fnNameIdent != null && fnNameIdent.length() > 0) { scopeContext.globalNameFor(fnNameIdent); } while (fromParamNode != null) { String fromParamName = fromParamNode.getString(); JsName name = scopeContext.localNameFor(fromParamName); toFn.getParameters().add(new JsParameter(name)); fromParamNode = fromParamNode.getNext(); } // Map the function's body. // JsBlock toBody = mapBlock(fromBodyNode); toFn.setBody(toBody); scopeContext.exitFunction(); return toFn; }
private JsTry mapTryStatement(Node tryNode) throws JsParserException { JsTry toTry = new JsTry(); // Map the "try" body. // Node fromTryBody = tryNode.getFirstChild(); toTry.setTryBlock(mapBlock(fromTryBody)); // Map zero or more catch blocks. // Node fromCatchNodes = fromTryBody.getNext(); Node fromCatchNode = fromCatchNodes.getFirstChild(); while (fromCatchNode != null) { assert (fromCatchNode.getType() == TokenStream.CATCH); // Map the catch variable. // Node fromCatchVarName = fromCatchNode.getFirstChild(); JsCatch catchBlock = scopeContext.enterCatch(fromCatchVarName.getString()); // Pre-advance to the next catch block, if any. // We do this here to decide whether or not this is the last one. // fromCatchNode = fromCatchNode.getNext(); // Map the condition, with a little fixup based on whether or not // this is the last catch block. // Node fromCondition = fromCatchVarName.getNext(); JsExpression toCondition = mapExpression(fromCondition); catchBlock.setCondition(toCondition); if (fromCatchNode == null) { if (toCondition instanceof JsBooleanLiteral) { if (((JsBooleanLiteral) toCondition).getValue()) { // Actually, this is an unconditional catch block. // Indicate that by nulling the condition. // catchBlock.setCondition(null); } } } // Map the catch body. // Node fromCatchBody = fromCondition.getNext(); catchBlock.setBody(mapBlock(fromCatchBody)); // Attach it. // toTry.getCatches().add(catchBlock); scopeContext.exitCatch(); } Node fromFinallyNode = fromCatchNodes.getNext(); if (fromFinallyNode != null) { toTry.setFinallyBlock(mapBlock(fromFinallyNode)); } return toTry; }
private JsLabel mapLabel(Node labelNode) throws JsParserException { String fromName = labelNode.getFirstChild().getString(); JsName toName = scopeContext.enterLabel(fromName); Node fromStmt = labelNode.getFirstChild().getNext(); JsLabel toLabel = new JsLabel(toName); toLabel.setStatement(mapStatement(fromStmt)); scopeContext.exitLabel(); return toLabel; }
/** Produces a {@link JsNameRef}. */ private JsNameRef mapAsPropertyNameRef(Node nameRefNode) throws JsParserException { JsNode unknown = map(nameRefNode); // This is weird, but for "a.b", the rhino AST calls "b" a string literal. // However, since we know it's for a PROPGET, we can unstringliteralize it. // if (unknown instanceof JsStringLiteral) { JsStringLiteral lit = (JsStringLiteral) unknown; return scopeContext.referenceFor(lit.getValue()); } else { throw createParserException("Expecting a name reference", nameRefNode); } }
private JsNameRef mapGetProp(Node getPropNode) throws JsParserException { Node from1 = getPropNode.getFirstChild(); Node from2 = from1.getNext(); JsExpression toQualifier = mapExpression(from1); JsNameRef toNameRef; if (from2 != null) { toNameRef = mapAsPropertyNameRef(from2); } else { // Special properties don't have a second expression. // Object obj = getPropNode.getProp(Node.SPECIAL_PROP_PROP); assert (obj instanceof String); toNameRef = scopeContext.referenceFor((String) obj); } toNameRef.setQualifier(toQualifier); return toNameRef; }
@Nullable private JsNameRef getTargetLabel(@NotNull Node statementWithLabel) { int type = statementWithLabel.getType(); if (type != TokenStream.BREAK && type != TokenStream.CONTINUE) { String tokenTypeName = TokenStream.tokenToName(statementWithLabel.getType()); throw new AssertionError("Unexpected node type with label: " + tokenTypeName); } Node label = statementWithLabel.getFirstChild(); if (label == null) return null; String identifier = label.getString(); assert identifier != null : "If label exists identifier should not be null"; JsName labelName = scopeContext.labelFor(identifier); assert labelName != null : "Unknown label name: " + identifier; return labelName.makeRef(); }
private JsVars mapVar(Node varNode) throws JsParserException { JsVars toVars = new JsVars(); Node fromVar = varNode.getFirstChild(); while (fromVar != null) { // Use a conservative name allocation strategy that allocates all names // from the function's scope, even the names of properties in field // literals. // String fromName = fromVar.getString(); JsName toName = scopeContext.localNameFor(fromName); JsVars.JsVar toVar = new JsVars.JsVar(toName); Node fromInit = fromVar.getFirstChild(); if (fromInit != null) { JsExpression toInit = mapExpression(fromInit); toVar.setInitExpression(toInit); } toVars.add(toVar); fromVar = fromVar.getNext(); } return toVars; }
private JsStatement mapForStatement(Node forNode) throws JsParserException { Node fromInit = forNode.getFirstChild(); Node fromTest = fromInit.getNext(); Node fromIncr = fromTest.getNext(); Node fromBody = fromIncr.getNext(); if (fromBody == null) { // This could be a "for...in" structure. // We could based on the different child layout. // Node fromIter = forNode.getFirstChild(); Node fromObjExpr = fromIter.getNext(); fromBody = fromObjExpr.getNext(); JsForIn toForIn; if (fromIter.getType() == TokenStream.VAR) { // A named iterator var. // Node fromIterVarName = fromIter.getFirstChild(); String fromName = fromIterVarName.getString(); JsName toName = scopeContext.localNameFor(fromName); toForIn = new JsForIn(toName); Node fromIterInit = fromIterVarName.getFirstChild(); if (fromIterInit != null) { // That has an initializer expression (useful only for side effects). // toForIn.setIterExpression(mapOptionalExpression(fromIterInit)); } } else { // An unnamed iterator var. // toForIn = new JsForIn(); toForIn.setIterExpression(mapExpression(fromIter)); } toForIn.setObjectExpression(mapExpression(fromObjExpr)); // The body stmt. // JsStatement bodyStmt = mapStatement(fromBody); if (bodyStmt != null) { toForIn.setBody(bodyStmt); } else { toForIn.setBody(JsEmpty.INSTANCE$); } return toForIn; } else { // Regular ol' for loop. // JsFor toFor; // The first item is either an expression or a JsVars. JsNode init = map(fromInit); JsExpression condition = mapOptionalExpression(fromTest); JsExpression increment = mapOptionalExpression(fromIncr); assert (init != null); if (init instanceof JsVars) { toFor = new JsFor((JsVars) init, condition, increment); } else { assert (init instanceof JsExpression); toFor = new JsFor((JsExpression) init, condition, increment); } JsStatement bodyStmt = mapStatement(fromBody); if (bodyStmt != null) { toFor.setBody(bodyStmt); } else { toFor.setBody(JsEmpty.INSTANCE$); } return toFor; } }
private JsNode map(Node node) throws JsParserException { switch (node.getType()) { case TokenStream.SCRIPT: { JsBlock block = new JsBlock(); mapStatements(block.getStatements(), node); return block; } case TokenStream.DEBUGGER: return mapDebuggerStatement(node); case TokenStream.VOID: // VOID = nothing was parsed for this node return null; case TokenStream.EXPRSTMT: return mapExpressionStatement(node); case TokenStream.REGEXP: return mapRegExp(node); case TokenStream.ADD: return mapBinaryOperation(JsBinaryOperator.ADD, node); case TokenStream.SUB: return mapBinaryOperation(JsBinaryOperator.SUB, node); case TokenStream.MUL: return mapBinaryOperation(JsBinaryOperator.MUL, node); case TokenStream.DIV: return mapBinaryOperation(JsBinaryOperator.DIV, node); case TokenStream.MOD: return mapBinaryOperation(JsBinaryOperator.MOD, node); case TokenStream.AND: return mapBinaryOperation(JsBinaryOperator.AND, node); case TokenStream.OR: return mapBinaryOperation(JsBinaryOperator.OR, node); case TokenStream.BITAND: return mapBinaryOperation(JsBinaryOperator.BIT_AND, node); case TokenStream.BITOR: return mapBinaryOperation(JsBinaryOperator.BIT_OR, node); case TokenStream.BITXOR: return mapBinaryOperation(JsBinaryOperator.BIT_XOR, node); case TokenStream.ASSIGN: return mapAssignmentVariant(node); case TokenStream.RELOP: return mapRelationalVariant(node); case TokenStream.EQOP: return mapEqualityVariant(node); case TokenStream.SHOP: return mapShiftVariant(node); case TokenStream.UNARYOP: return mapUnaryVariant(node); case TokenStream.INC: return mapIncDecFixity(JsUnaryOperator.INC, node); case TokenStream.DEC: return mapIncDecFixity(JsUnaryOperator.DEC, node); case TokenStream.HOOK: return mapConditional(node); case TokenStream.STRING: return program.getStringLiteral(node.getString()); case TokenStream.NUMBER_INT: return mapIntNumber(node); case TokenStream.NUMBER: return mapDoubleNumber(node); case TokenStream.CALL: return mapCall(node); case TokenStream.GETPROP: return mapGetProp(node); case TokenStream.SETPROP: return mapSetProp(node); case TokenStream.DELPROP: return mapDeleteProp(node); case TokenStream.IF: return mapIfStatement(node); case TokenStream.WHILE: return mapDoOrWhileStatement(true, node); case TokenStream.DO: return mapDoOrWhileStatement(false, node); case TokenStream.FOR: return mapForStatement(node); case TokenStream.WITH: return mapWithStatement(node); case TokenStream.GETELEM: return mapGetElem(node); case TokenStream.SETELEM: return mapSetElem(node); case TokenStream.FUNCTION: return mapFunction(node); case TokenStream.BLOCK: return mapBlock(node); case TokenStream.SETNAME: return mapBinaryOperation(JsBinaryOperator.ASG, node); case TokenStream.NAME: case TokenStream.BINDNAME: return scopeContext.globalNameFor(node.getString()).makeRef(); case TokenStream.RETURN: return mapReturn(node); case TokenStream.BREAK: return mapBreak(node); case TokenStream.CONTINUE: return mapContinue(node); case TokenStream.OBJLIT: return mapObjectLit(node); case TokenStream.ARRAYLIT: return mapArrayLit(node); case TokenStream.VAR: return mapVar(node); case TokenStream.PRIMARY: return mapPrimary(node); case TokenStream.COMMA: return mapBinaryOperation(JsBinaryOperator.COMMA, node); case TokenStream.NEW: return mapNew(node); case TokenStream.THROW: return mapThrowStatement(node); case TokenStream.TRY: return mapTryStatement(node); case TokenStream.SWITCH: return mapSwitchStatement(node); case TokenStream.LABEL: return mapLabel(node); default: int tokenType = node.getType(); throw createParserException("Unexpected top-level token type: " + tokenType, node); } }