1   // Copyright 2012- Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.util.ArrayList;
6   
7   import static jminusminus.CLConstants.*;
8   
9   /**
10   * The AST node for a constructor declaration.
11   */
12  class JConstructorDeclaration extends JMethodDeclaration implements JMember {
13      // Does this constructor invoke this(...) or super(...)?
14      private boolean invokesConstructor;
15  
16      // Defining class
17      private JClassDeclaration definingClass;
18  
19      /**
20       * Constructs an AST node for a constructor declaration.
21       *
22       * @param line       line in which the constructor declaration occurs in the source file.
23       * @param mods       modifiers.
24       * @param name       constructor name.
25       * @param params     the formal parameters.
26       * @param exceptions exceptions thrown.
27       * @param body       constructor body.
28       */
29      public JConstructorDeclaration(int line, ArrayList<String> mods, String name,
30                                     ArrayList<JFormalParameter> params,
31                                     ArrayList<TypeName> exceptions, JBlock body) {
32          super(line, mods, name, Type.CONSTRUCTOR, params, exceptions, body);
33      }
34  
35      /**
36       * {@inheritDoc}
37       */
38      public void preAnalyze(Context context, CLEmitter partial) {
39          super.preAnalyze(context, partial);
40          if (isStatic) {
41              JAST.compilationUnit.reportSemanticError(line(), "Constructor cannot be static");
42          } else if (isAbstract) {
43              JAST.compilationUnit.reportSemanticError(line(), "Constructor cannot be abstract");
44          }
45          if (body.statements().size() > 0 &&
46                  body.statements().get(0) instanceof JStatementExpression) {
47              JStatementExpression first = (JStatementExpression) body.statements().get(0);
48              if (first.expr instanceof JSuperConstruction) {
49                  ((JSuperConstruction) first.expr).markProperUseOfConstructor();
50                  invokesConstructor = true;
51              } else if (first.expr instanceof JThisConstruction) {
52                  ((JThisConstruction) first.expr).markProperUseOfConstructor();
53                  invokesConstructor = true;
54              }
55          }
56      }
57  
58      /**
59       * {@inheritDoc}
60       */
61      public JAST analyze(Context context) {
62          // Record the defining class declaration.
63          definingClass = (JClassDeclaration) (context.classContext().definition());
64  
65          MethodContext methodContext = new MethodContext(context, isStatic, returnType);
66          this.context = methodContext;
67  
68          if (!isStatic) {
69              // Offset 0 is used to address "this".
70              this.context.nextOffset();
71          }
72  
73          // Declare the parameters. We consider a formal parameter to be always initialized, via a
74          // method call.
75          for (JFormalParameter param : params) {
76              LocalVariableDefn defn = new LocalVariableDefn(param.type(), this.context.nextOffset());
77              defn.initialize();
78              this.context.addEntry(param.line(), param.name(), defn);
79          }
80  
81          if (body != null) {
82              body = body.analyze(this.context);
83          }
84          return this;
85      }
86  
87      /**
88       * {@inheritDoc}
89       */
90      public void partialCodegen(Context context, CLEmitter partial) {
91          partial.addMethod(mods, "<init>", descriptor, null, false);
92          if (!invokesConstructor) {
93              partial.addNoArgInstruction(ALOAD_0);
94              partial.addMemberAccessInstruction(INVOKESPECIAL,
95                      ((JClassDeclaration) context.classContext().definition()).superType().jvmName(),
96                      "<init>", "()V");
97          }
98          partial.addNoArgInstruction(RETURN);
99      }
100 
101     /**
102      * {@inheritDoc}
103      */
104     public void codegen(CLEmitter output) {
105         output.addMethod(mods, "<init>", descriptor, null, false);
106         if (!invokesConstructor) {
107             output.addNoArgInstruction(ALOAD_0);
108             output.addMemberAccessInstruction(INVOKESPECIAL, definingClass.superType().jvmName(),
109                     "<init>", "()V");
110         }
111 
112         // Field initializations.
113         for (JFieldDeclaration field : definingClass.instanceFieldInitializations()) {
114             field.codegenInitializations(output);
115         }
116 
117         // And then the body.
118         body.codegen(output);
119 
120         output.addNoArgInstruction(RETURN);
121     }
122 
123     /**
124      * {@inheritDoc}
125      */
126     public void toJSON(JSONElement json) {
127         JSONElement e = new JSONElement();
128         json.addChild("JConstructorDeclaration:" + line, e);
129         e.addAttribute("name", name);
130         if (mods != null) {
131             ArrayList<String> value = new ArrayList<String>();
132             for (String mod : mods) {
133                 value.add(String.format("\"%s\"", mod));
134             }
135             e.addAttribute("modifiers", value);
136         }
137         if (params != null) {
138             ArrayList<String> value = new ArrayList<String>();
139             for (JFormalParameter param : params) {
140                 value.add(String.format("[\"%s\", \"%s\"]", param.name(),
141                         param.type() == null ? "" : param.type().toString()));
142             }
143             e.addAttribute("parameters", value);
144         }
145         if (exceptions != null) {
146             ArrayList<String> value = new ArrayList<String>();
147             for (TypeName exception : exceptions) {
148                 value.add(String.format("\"%s\"", exception.toString()));
149             }
150             e.addAttribute("throws", value);
151         }
152         if (context != null) {
153             context.toJSON(e);
154         }
155         if (body != null) {
156             body.toJSON(e);
157         }
158     }
159 }
160