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 an identifier used as a primary expression.
9    */
10  class JVariable extends JExpression implements JLhs {
11      // The variable's name.
12      private String name;
13  
14      // The variable's definition.
15      private IDefn iDefn;
16  
17      // Was analyzeLhs() done?
18      private boolean analyzeLhs;
19  
20      /**
21       * Constructs the AST node for a variable.
22       *
23       * @param line line in which the variable occurs in the source file.
24       * @param name the name.
25       */
26      public JVariable(int line, String name) {
27          super(line);
28          this.name = name;
29      }
30  
31      /**
32       * Returns the identifier name.
33       *
34       * @return the identifier name.
35       */
36      public String name() {
37          return name;
38      }
39  
40      /**
41       * Returns the identifier's definition.
42       *
43       * @return the identifier's definition.
44       */
45      public IDefn iDefn() {
46          return iDefn;
47      }
48  
49      /**
50       * {@inheritDoc}
51       */
52      public JExpression analyze(Context context) {
53          iDefn = context.lookup(name);
54          if (iDefn == null) {
55              // Not a local, but is it a field?
56              Type definingType = context.definingType();
57              Field field = definingType.fieldFor(name);
58              if (field == null) {
59                  type = Type.ANY;
60                  JAST.compilationUnit.reportSemanticError(line, "Cannot find name: " + name);
61              } else {
62                  // Rewrite a variable denoting a field as an explicit field selection.
63                  type = field.type();
64                  JExpression newTree = new JFieldSelection(line(),
65                          field.isStatic() || (context.methodContext() != null &&
66                                  context.methodContext().isStatic()) ?
67                                  new JVariable(line(), definingType.toString()) : new JThis(line),
68                          name);
69                  return (JExpression) newTree.analyze(context);
70              }
71          } else {
72              if (!analyzeLhs && iDefn instanceof LocalVariableDefn &&
73                      !((LocalVariableDefn) iDefn).isInitialized()) {
74                  JAST.compilationUnit.reportSemanticError(line, "Variable " + name +
75                          " might not have been initialized");
76              }
77              type = iDefn.type();
78          }
79          return this;
80      }
81  
82      /**
83       * {@inheritDoc}
84       */
85      public JExpression analyzeLhs(Context context) {
86          analyzeLhs = true;
87          JExpression newTree = analyze(context);
88          if (newTree instanceof JVariable) {
89              // Could (now) be a JFieldSelection, but if it's (still) a JVariable...
90              if (iDefn != null && !(iDefn instanceof LocalVariableDefn)) {
91                  JAST.compilationUnit.reportSemanticError(line(), name + " is a bad LHS to a =");
92              }
93          }
94          return newTree;
95      }
96  
97      /**
98       * {@inheritDoc}
99       */
100     public void codegen(CLEmitter output) {
101         if (iDefn instanceof LocalVariableDefn) {
102             int offset = ((LocalVariableDefn) iDefn).offset();
103             if (type.isReference()) {
104                 switch (offset) {
105                     case 0:
106                         output.addNoArgInstruction(ALOAD_0);
107                         break;
108                     case 1:
109                         output.addNoArgInstruction(ALOAD_1);
110                         break;
111                     case 2:
112                         output.addNoArgInstruction(ALOAD_2);
113                         break;
114                     case 3:
115                         output.addNoArgInstruction(ALOAD_3);
116                         break;
117                     default:
118                         output.addOneArgInstruction(ALOAD, offset);
119                         break;
120                 }
121             } else {
122                 // Primitive types.
123                 if (type == Type.INT || type == Type.BOOLEAN || type == Type.CHAR) {
124                     switch (offset) {
125                         case 0:
126                             output.addNoArgInstruction(ILOAD_0);
127                             break;
128                         case 1:
129                             output.addNoArgInstruction(ILOAD_1);
130                             break;
131                         case 2:
132                             output.addNoArgInstruction(ILOAD_2);
133                             break;
134                         case 3:
135                             output.addNoArgInstruction(ILOAD_3);
136                             break;
137                         default:
138                             output.addOneArgInstruction(ILOAD, offset);
139                             break;
140                     }
141                 }
142             }
143         }
144     }
145 
146     /**
147      * {@inheritDoc}
148      */
149     public void codegen(CLEmitter output, String targetLabel, boolean onTrue) {
150         if (iDefn instanceof LocalVariableDefn) {
151             codegen(output);
152             if (onTrue) {
153                 output.addBranchInstruction(IFNE, targetLabel);
154             } else {
155                 output.addBranchInstruction(IFEQ, targetLabel);
156             }
157         }
158     }
159 
160     /**
161      * {@inheritDoc}
162      */
163     public void codegenLoadLhsLvalue(CLEmitter output) {
164         // Nothing here.
165     }
166 
167     /**
168      * {@inheritDoc}
169      */
170     public void codegenLoadLhsRvalue(CLEmitter output) {
171         codegen(output);
172     }
173 
174     /**
175      * {@inheritDoc}
176      */
177     public void codegenDuplicateRvalue(CLEmitter output) {
178         if (iDefn instanceof LocalVariableDefn) {
179             // It's copied atop the stack.
180             output.addNoArgInstruction(DUP);
181         }
182     }
183 
184     /**
185      * {@inheritDoc}
186      */
187     public void codegenStore(CLEmitter output) {
188         if (iDefn instanceof LocalVariableDefn) {
189             int offset = ((LocalVariableDefn) iDefn).offset();
190             if (type.isReference()) {
191                 switch (offset) {
192                     case 0:
193                         output.addNoArgInstruction(ASTORE_0);
194                         break;
195                     case 1:
196                         output.addNoArgInstruction(ASTORE_1);
197                         break;
198                     case 2:
199                         output.addNoArgInstruction(ASTORE_2);
200                         break;
201                     case 3:
202                         output.addNoArgInstruction(ASTORE_3);
203                         break;
204                     default:
205                         output.addOneArgInstruction(ASTORE, offset);
206                         break;
207                 }
208             } else {
209                 // Primitive types.
210                 if (type == Type.INT || type == Type.BOOLEAN || type == Type.CHAR) {
211                     switch (offset) {
212                         case 0:
213                             output.addNoArgInstruction(ISTORE_0);
214                             break;
215                         case 1:
216                             output.addNoArgInstruction(ISTORE_1);
217                             break;
218                         case 2:
219                             output.addNoArgInstruction(ISTORE_2);
220                             break;
221                         case 3:
222                             output.addNoArgInstruction(ISTORE_3);
223                             break;
224                         default:
225                             output.addOneArgInstruction(ISTORE, offset);
226                             break;
227                     }
228                 }
229             }
230         }
231     }
232 
233     /**
234      * {@inheritDoc}
235      */
236     public void toJSON(JSONElement json) {
237         JSONElement e = new JSONElement();
238         json.addChild("JVariable:" + line, e);
239         e.addAttribute("name", name());
240     }
241 }
242