private AstNode statement() throws IOException { int pos = ts.tokenBeg; try { AstNode pn = statementHelper(); if (pn != null) { if (compilerEnv.isStrictMode() && !pn.hasSideEffects()) { int beg = pn.getPosition(); beg = Math.max(beg, lineBeginningFor(beg)); addStrictWarning(pn instanceof EmptyStatement ? "msg.extra.trailing.semi" : "msg.no.side.effects", "", beg, nodeEnd(pn) - beg); } return pn; } } catch (ParserException e) { // an ErrorNode was added to the ErrorReporter } // error: skip ahead to a probable statement boundary guessingStatementEnd: for (;;) { int tt = peekTokenOrEOL(); consumeToken(); switch (tt) { case Token.ERROR: case Token.EOF: case Token.EOL: case Token.SEMI: break guessingStatementEnd; } } // We don't make error nodes explicitly part of the tree; // they get added to the ErrorReporter. May need to do // something different here. return new EmptyStatement(pos, ts.tokenBeg - pos); }
/** * For a {@link FunctionNode} representing a constructor, if the constructor C is * followed by a sequence of assignments of the form C.prototype.a = ...;, return * a set of all the properties written on the prototype. If the assignments do not * fit that form, return the empty set. * @param consNode * @return */ public static Set<String> getWrittenPrototypeProps(FunctionNode consNode) { Set<String> result = HashSetFactory.make(); AstNode parent = consNode.getParent(); boolean found = false; for (Node child: parent) { if (child instanceof EmptyStatement) { continue; } if (child.equals(consNode)) { found = true; } else if (found) { // looking for a statement of the form C.prototype.a = ...; boolean foundAssign = false; if (child instanceof ExpressionStatement) { AstNode expression = ((ExpressionStatement)child).getExpression(); if (expression instanceof Assignment) { Assignment assign = (Assignment) expression; AstNode lhs = assign.getLeft(); if (lhs instanceof PropertyGet) { PropertyGet pg = (PropertyGet) lhs; AstNode pgTarget = pg.getTarget(); if (pgTarget instanceof PropertyGet) { PropertyGet basePG = (PropertyGet) pgTarget; if (basePG.getProperty().getIdentifier().equals("prototype")) { // BINGO result.add(pg.getProperty().getIdentifier()); foundAssign = true; } } } } } if (!foundAssign) { // stop looking for more assignments break; } } } return result; }
/** * 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; }