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