| JReturnStatement.java |
1 // Copyright 2012- 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 is non-void, then there is a
9 * value to return, so we keep track of the expression denoting that value and its type.
10 */
11 class JReturnStatement extends JStatement {
12 // The returned expression.
13 private JExpression expr;
14
15 /**
16 * Constructs an AST node for a return-statement.
17 *
18 * @param line line in which the return-statement appears in the source file.
19 * @param expr the returned expression.
20 */
21 public JReturnStatement(int line, JExpression expr) {
22 super(line);
23 this.expr = expr;
24 }
25
26 /**
27 * {@inheritDoc}
28 */
29 public JStatement analyze(Context context) {
30 MethodContext methodContext = context.methodContext();
31
32 // The methodContext can be null if return statement occurs in a block that is not within
33 // a method. For example, in the Java grammar, return statement, at least syntactically,
34 // can occur in a static block. But since j-- does not allow a block to occur outside of a
35 // method, we don't check for methodContext being null.
36 if (methodContext.methodReturnType() == Type.CONSTRUCTOR) {
37 if (expr != null) {
38 // Can't return a value from a constructor.
39 JAST.compilationUnit.reportSemanticError(line(),
40 "Cannot return a value from a constructor");
41 }
42 } else {
43 // Must be a method.
44 Type returnType = methodContext.methodReturnType();
45 methodContext.confirmMethodHasReturn();
46 if (expr != null) {
47 if (returnType == Type.VOID) {
48 // Can't return a value from void method.
49 JAST.compilationUnit.reportSemanticError(line(),
50 "Cannot return a value from a void method");
51 } else {
52 // There's a (non-void) return value. Its type must match the return type of
53 // the method.
54 expr = expr.analyze(context);
55 expr.type().mustMatchExpected(line(), returnType);
56 }
57 } else {
58 // The method better have void as return type.
59 if (returnType != Type.VOID) {
60 JAST.compilationUnit.reportSemanticError(line(), "Missing return value");
61 }
62 }
63 }
64 return this;
65 }
66
67 /**
68 * {@inheritDoc}
69 */
70 public void codegen(CLEmitter output) {
71 if (expr == null) {
72 output.addNoArgInstruction(RETURN);
73 } else {
74 expr.codegen(output);
75 if (expr.type() == Type.INT || expr.type() == Type.BOOLEAN ||
76 expr.type() == Type.CHAR) {
77 output.addNoArgInstruction(IRETURN);
78 } else {
79 output.addNoArgInstruction(ARETURN);
80 }
81 }
82 }
83
84 /**
85 * {@inheritDoc}
86 */
87 public void toJSON(JSONElement json) {
88 JSONElement e = new JSONElement();
89 json.addChild("JReturnStatement:" + line, e);
90 if (expr != null) {
91 JSONElement e1 = new JSONElement();
92 e.addChild("Expression", e1);
93 expr.toJSON(e1);
94 }
95 }
96 }
97