JReturnStatement.java |
1 // Copyright 2011 Bill Campbell, Swami Iyer and Bahar Akbal-Delibas 2 3 package jminusminus; 4 5 import static jminusminus.CLConstants.*; 6 7 /** 8 * The AST node for a return-statement. If the enclosing method 9 * in non-void, then there is a value to return, so we keep track 10 * of the expression denoting that value and its type. 11 */ 12 13 class JReturnStatement 14 extends JStatement { 15 16 /** The returned expression. */ 17 private JExpression expr; 18 19 /** 20 * Construct an AST node for a return-statement given its 21 * line number, and the expression that is returned. 22 * 23 * @param line 24 * line in which the return-statement appears 25 * in the source file. 26 * @param expr 27 * the returned expression. 28 */ 29 30 public JReturnStatement(int line, JExpression expr) { 31 super(line); 32 this.expr = expr; 33 } 34 35 /** 36 * Analysis distinguishes between our being in a constructor 37 * or in a regular method in checking return types. In the 38 * case of a return expression, analyze it and check types. 39 * Determine the (possibly void) return type. 40 * 41 * @param context 42 * context in which names are resolved. 43 * @return the analyzed (and possibly rewritten) AST subtree. 44 */ 45 46 public JStatement analyze(Context context) { 47 MethodContext methodContext = context.methodContext(); 48 49 // The methodContext can be null if return statement 50 // occurs 51 // in a block that is not within a method. For example, 52 // in 53 // the Java grammar, return statement, at least 54 // syntactically, can occur in a static block. But since 55 // j-- does not allow a block to occur outside of a 56 // method, 57 // we don't check for methodContext being null 58 59 if (methodContext.methodReturnType() == Type.CONSTRUCTOR) { 60 if (expr != null) { 61 // Can't return a value from a constructor 62 JAST.compilationUnit.reportSemanticError(line(), 63 "cannot return a value from a constructor"); 64 } 65 } else { 66 // Must be a method 67 Type returnType = methodContext.methodReturnType(); 68 methodContext.confirmMethodHasReturn(); 69 if (expr != null) { 70 if (returnType == Type.VOID) { 71 // Can't return a value from void method 72 JAST.compilationUnit.reportSemanticError(line(), 73 "cannot return a value from a void method"); 74 } else { 75 // There's a (non-void) return expression. 76 // Its 77 // type must match the return type of the 78 // method 79 expr = expr.analyze(context); 80 expr.type().mustMatchExpected(line(), returnType); 81 } 82 } else { 83 // The method better have void as return type 84 if (returnType != Type.VOID) { 85 JAST.compilationUnit.reportSemanticError(line(), 86 "missing return value"); 87 } 88 } 89 } 90 return this; 91 } 92 93 /** 94 * Generate code for the return statement. In the case of 95 * void method types, generate a simple (void) return. In the 96 * case of a return expression, generate code to load that 97 * onto the stack and then generate the appropriate return 98 * instruction. 99 * 100 * @param output 101 * the code emitter (basically an abstraction 102 * for producing the .class file). 103 */ 104 105 public void codegen(CLEmitter output) { 106 if (expr == null) { 107 output.addNoArgInstruction(RETURN); 108 } else { 109 expr.codegen(output); 110 if (expr.type() == Type.INT 111 || expr.type() == Type.BOOLEAN 112 || expr.type() == Type.CHAR) { 113 output.addNoArgInstruction(IRETURN); 114 } else { 115 output.addNoArgInstruction(ARETURN); 116 } 117 } 118 } 119 120 /** 121 * @inheritDoc 122 */ 123 124 public void writeToStdOut(PrettyPrinter p) { 125 if (expr != null) { 126 p.printf("<JReturnStatement line=\"%d\">\n", line()); 127 p.indentRight(); 128 expr.writeToStdOut(p); 129 p.indentLeft(); 130 p.printf("</JReturnStatement>\n"); 131 } else { 132 p.printf("<JReturnStatement line=\"%d\"/>\n", line()); 133 } 134 } 135 } 136