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