private Node transformReturn(ReturnStatement node) { boolean expClosure = Boolean.TRUE.equals(node.getProp(Node.EXPRESSION_CLOSURE_PROP)); boolean isArrow = Boolean.TRUE.equals(node.getProp(Node.ARROW_FUNCTION_PROP)); if (expClosure) { if (!isArrow) { decompiler.addName(" "); } } else { decompiler.addToken(Token.RETURN); } AstNode rv = node.getReturnValue(); Node value = rv == null ? null : transform(rv); if (!expClosure) decompiler.addEOL(Token.SEMI); return rv == null ? new Node(Token.RETURN, node.getLineno()) : new Node(Token.RETURN, value, node.getLineno()); }
/** * generate constraints for return statements */ private void processReturnStatement(ReturnStatement rs) throws Error { FunctionNode fun = ConstraintGenUtil.findEnclosingFunction(rs); FunctionTerm.FunctionKind funType = ConstraintGenUtil.isConstructor(fun) ? FunctionTerm.FunctionKind.Constructor : (ConstraintGenUtil.isMethod(fun) ? FunctionTerm.FunctionKind.Method : FunctionTerm.FunctionKind.Function); ITypeTerm funTerm = findOrCreateFunctionTerm(fun, funType); ITypeTerm returnTerm = findOrCreateFunctionReturnTerm(funTerm, fun.getParamCount(), rs.getLineno(), null); AstNode exp = rs.getReturnValue(); if (exp != null){ ITypeTerm expTerm = processExpression(exp); addSubTypeConstraint(expTerm, returnTerm, rs.getLineno(), (solution) -> subtypeError("bad return value " + shortSrc(exp), solution.typeOfTerm(expTerm), solution.typeOfTerm(returnTerm), locationOf(rs))); } else { ITypeTerm voidTerm = findOrCreateTypeTerm(new VoidType(), rs.getLineno()); addTypeEqualityConstraint(voidTerm, returnTerm, rs.getLineno(), (solution) -> genericTypeError("missing return value", locationOf(rs)) .withNote("expected " + describeTypeOf(returnTerm, solution))); } }
private void print(FunctionNode node) throws IOException { if (!node.isMethod()) { writer.append("function"); } if (node.getFunctionName() != null) { writer.append(' '); print(node.getFunctionName()); } writer.append('('); printList(node.getParams()); writer.append(')').ws(); if (node.isExpressionClosure()) { if (node.getBody().getLastChild() instanceof ReturnStatement) { print(((ReturnStatement) node.getBody().getLastChild()).getReturnValue()); if (node.getFunctionType() == FunctionNode.FUNCTION_STATEMENT) { writer.append(";"); } } } else { print(node.getBody()); } }
/** * Iterate through all the return types and check they are all the same, * otherwise return no type * * @return */ public TypeDeclaration getCommonReturnType() { TypeDeclaration commonType = null; for (ReturnStatement rs : returnStatements) { AstNode returnValue = rs.getReturnValue(); // resolve the node TypeDeclaration type = provider.getJavaScriptEngine() .getJavaScriptResolver(provider).resolveNode( returnValue); if (commonType == null) { commonType = type; } else { if (!commonType.equals(type)) { commonType = provider.getTypesFactory() .getDefaultTypeDeclaration(); break; // not matching } } } return commonType; }
@Override public boolean visit(AstNode node) { if (node instanceof ReturnStatement){ ReturnStatement rs = (ReturnStatement)node; if (rs.getReturnValue() != null){ if (ConstraintGenUtil.findEnclosingFunction(node) == fun){ returnsValue = true; } } } return true; }
private void print(ReturnStatement node) throws IOException { writer.append("return"); if (node.getReturnValue() != null) { writer.append(' '); print(node.getReturnValue()); } writer.append(';'); }
private static AstNode getExpression(MethodReference method, AstNode statement) { if (method.getReturnType() == ValueType.VOID) { if (statement instanceof ExpressionStatement) { return ((ExpressionStatement) statement).getExpression(); } else if (statement instanceof ThrowStatement) { return ((ThrowStatement) statement).getExpression(); } } else { if (statement instanceof ReturnStatement) { return ((ReturnStatement) statement).getReturnValue(); } } return null; }
@Override public boolean visit(AstNode node) { switch (node.getType()) { case Token.RETURN: returnStatements.add((ReturnStatement)node); break; } return true; }
/** * 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; }