private Node transformNewExpr(NewExpression node) { decompiler.addToken(Token.NEW); Node nx = createCallOrNew(Token.NEW, transform(node.getTarget())); nx.setLineno(node.getLineno()); List<AstNode> args = node.getArguments(); decompiler.addToken(Token.LP); for (int i = 0; i < args.size(); i++) { AstNode arg = args.get(i); nx.addChildToBack(transform(arg)); if (i < args.size() - 1) { decompiler.addToken(Token.COMMA); } } decompiler.addToken(Token.RP); if (node.getInitializer() != null) { nx.addChildToBack(transformObjectLiteral(node.getInitializer())); } return nx; }
/** * constructor call */ private void processNewExpression(NewExpression ne) { processFunctionCall(ne); // in `new X(...)`, the target X must be a constructor ITypeTerm target = processExpression(ne.getTarget()); int nrParams = ne.getArguments().size(); List<Type> paramTypes = new ArrayList<>(nrParams); List<String> paramNames = new ArrayList<>(nrParams); for (int i = 0; i < nrParams; i++) { paramTypes.add(factory.freshTypeVar()); paramNames.add("arg" + i); } Type returnType = factory.freshTypeVar(); Type protoType = factory.freshTypeVar(); Type ctorType = new ConstructorType(paramTypes, paramNames, returnType, protoType); addSubTypeConstraint(target, factory.getTermForType(ctorType), ne.getLineno(), null); }
/** * is right a valid expression to assign into the prototype field of a * constructor? currently we allow object literals, constructor calls, and * expressions of the form B.prototype * * @param right * @return */ private boolean validRHSForAssignToPrototype(AstNode right) { if (right instanceof ObjectLiteral || right instanceof NewExpression) { return true; } if (right instanceof PropertyGet) { PropertyGet pg = (PropertyGet) right; if (pg.getProperty().getIdentifier().equals("prototype")) { return true; } } return false; }
public static void checkFunctionCall(FunctionCallTerm t) { AstNode node = t.getNode(); if (node instanceof NewExpression) { ITypeTerm target = t.getTarget(); Type targetType = target.getType(); if (!Types.usableAsConstructor(targetType)) { throw new SolverException("invoking non-constructor function (type=" + targetType + ") with new (line " + node.getLineno() + ")"); } } }
private void handleFunctionReturnTerm( Consumer<IConstraint> constraintAdder, Set<Pair<ITypeTerm, Integer>> constrainedFunctionTerms, ITypeConstraint constraint) { FunctionReturnTerm returnTerm = (FunctionReturnTerm)(constraint.getLeft() instanceof FunctionReturnTerm ? constraint.getLeft() : constraint.getRight()); ITypeTerm otherTerm = constraint.getLeft() instanceof FunctionReturnTerm ? constraint.getRight() : constraint.getLeft(); ITypeTerm functionTerm = returnTerm.getFunctionTerm(); int nrParams = returnTerm.getNrParams(); // TODO make sure we handle constructors with parameters boolean isConstructorCall = otherTerm instanceof FunctionCallTerm && ((FunctionCallTerm)otherTerm).getFunctionCall() instanceof NewExpression; doConstraintsForFunctionTerm(constraintAdder, constrainedFunctionTerms, functionTerm, nrParams, isConstructorCall); }
private void print(FunctionCall node, int precedence) throws IOException { if (tryJavaInvocation(node)) { return; } if (precedence < PRECEDENCE_FUNCTION) { writer.append('('); } int innerPrecedence = node instanceof NewExpression ? PRECEDENCE_FUNCTION - 1 : PRECEDENCE_FUNCTION; if (node instanceof NewExpression) { writer.append("new "); } print(node.getTarget(), innerPrecedence); writer.append('('); printList(node.getArguments()); writer.append(')'); if (node instanceof NewExpression) { writer.ws(); NewExpression newExpr = (NewExpression) node; if (newExpr.getInitializer() != null) { print(newExpr.getInitializer()); } } if (precedence < PRECEDENCE_FUNCTION) { writer.append(')'); } }
/** * Returns the node name from 'Token.NEW' AstNode e.g new Object --> Object * new Date --> Date etc.. * * @param node NewExpression node * @return Extracts the Name identifier from NewExpression */ private static String findNewExpressionString(AstNode node) { NewExpression newEx = (NewExpression) node; AstNode target = newEx.getTarget(); String source = target.toSource(); int index = source.indexOf('('); if (index != -1) { source = source.substring(0, index); } return source; }
/** * Parse a new-expression, or if next token isn't {@link Token#NEW}, * a primary expression. * @param allowCallSyntax passed down to {@link #memberExprTail} */ private AstNode memberExpr(boolean allowCallSyntax) throws IOException { int tt = peekToken(), lineno = ts.lineno; AstNode pn; if (tt != Token.NEW) { pn = primaryExpr(); } else { consumeToken(); int pos = ts.tokenBeg; NewExpression nx = new NewExpression(pos); AstNode target = memberExpr(false); int end = getNodeEnd(target); nx.setTarget(target); int lp = -1; if (matchToken(Token.LP)) { lp = ts.tokenBeg; List<AstNode> args = argumentList(); if (args != null && args.size() > ARGC_LIMIT) reportError("msg.too.many.constructor.args"); int rp = ts.tokenBeg; end = ts.tokenEnd; if (args != null) nx.setArguments(args); nx.setParens(lp - pos, rp - pos); } // Experimental syntax: allow an object literal to follow a new // expression, which will mean a kind of anonymous class built with // the JavaAdapter. the object literal will be passed as an // additional argument to the constructor. if (matchToken(Token.LC)) { ObjectLiteral initializer = objectLiteral(); end = getNodeEnd(initializer); nx.setInitializer(initializer); } nx.setLength(end - pos); pn = nx; } pn.setLineno(lineno); AstNode tail = memberExprTail(allowCallSyntax, pn); return tail; }
/** * 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; }