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