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