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 for an array indexing operation. It has an expression denoting an
9    * array object and an expression denoting an integer index.
10   */
11  
12  class JArrayExpression extends JExpression implements JLhs {
13  
14      /** The array. */
15      private JExpression theArray;
16  
17      /** The array index expression. */
18      private JExpression indexExpr;
19  
20      /**
21       * Construct an AST node for an array indexing operation.
22       * 
23       * @param line
24       *            line in which the operation occurs in the source file.
25       * @param theArray
26       *            the array we're indexing.
27       * @param indexExpr
28       *            the index expression.
29       */
30  
31      public JArrayExpression(int line, JExpression theArray,
32              JExpression indexExpr) {
33          super(line);
34          this.theArray = theArray;
35          this.indexExpr = indexExpr;
36      }
37  
38      /**
39       * Perform semantic analysis on an array indexing expression such as A[i].
40       * 
41       * @param context
42       *            context in which names are resolved.
43       * @return the analyzed (and possibly rewritten) AST subtree.
44       */
45  
46      public JExpression analyze(Context context) {
47          theArray = (JExpression) theArray.analyze(context);
48          indexExpr = (JExpression) indexExpr.analyze(context);
49          if (!(theArray.type().isArray())) {
50              JAST.compilationUnit.reportSemanticError(line(),
51                      "attempt to index a non-array object");
52              this.type = Type.ANY;
53          } else {
54              this.type = theArray.type().componentType();
55          }
56          indexExpr.type().mustMatchExpected(line(), Type.INT);
57          return this;
58      }
59  
60      /**
61       * Analyzing the array expression as an Lvalue is like analyzing it for its
62       * Rvalue.
63       * 
64       * @param context
65       *            context in which names are resolved.
66       */
67  
68      public JExpression analyzeLhs(Context context) {
69          analyze(context);
70          return this;
71      }
72  
73      /**
74       * Perform code generation from the JArrayExpression using the specified
75       * code emitter. Generate the code necessary for loading the Rvalue.
76       * 
77       * @param output
78       *            the code emitter (basically an abstraction for producing the
79       *            .class file).
80       */
81  
82      public void codegen(CLEmitter output) {
83          theArray.codegen(output);
84          indexExpr.codegen(output);
85          if (type == Type.INT || type == Type.BOOLEAN || type == Type.CHAR) {
86              output.addNoArgInstruction(IALOAD);
87          } else if (!type.isPrimitive()) {
88              output.addNoArgInstruction(AALOAD);
89          }
90      }
91  
92      /**
93       * Generate the code required for setting up an Lvalue, eg for use in an
94       * assignment. Here, this requires loading the array and the index.
95       * 
96       * @param output
97       *            the code emitter (basically an abstraction for producing the
98       *            .class file).
99       */
100 
101     public void codegenLoadLhsLvalue(CLEmitter output) {
102         // Load the lvalue onto the stack: the array and the
103         // index.
104         theArray.codegen(output);
105         indexExpr.codegen(output);
106     }
107 
108     /**
109      * Generate the code required for loading an Rvalue for this variable, eg
110      * for use in a +=. Here, this requires duplicating the array and the index
111      * on the stack and doing an array load.
112      * 
113      * @param output
114      *            the code emitter (basically an abstraction for producing the
115      *            .class file).
116      */
117 
118     public void codegenLoadLhsRvalue(CLEmitter output) {
119         // Load rvalue onto stack, by duplicating the lvalue,
120         // and fetching it's content
121         if (type == Type.STRING) {
122             output.addNoArgInstruction(DUP2_X1);
123         } else {
124             output.addNoArgInstruction(DUP2);
125         }
126         if (type == Type.INT || type == Type.BOOLEAN || type == Type.CHAR) {
127             output.addNoArgInstruction(IALOAD);
128         } else if (!type.isPrimitive()) {
129             output.addNoArgInstruction(AALOAD);
130         }
131     }
132 
133     /**
134      * Generate the code required for duplicating the Rvalue that is on the
135      * stack becuase it is to be used in a surrounding expression, as in a[i] =
136      * x = <expr> or x = y--. Here this means copying it down two locations
137      * (beneath the array and index).
138      * 
139      * @param output
140      *            the code emitter (basically an abstraction for producing the
141      *            .class file).
142      */
143 
144     public void codegenDuplicateRvalue(CLEmitter output) {
145         // It's copied down below the array and index
146         output.addNoArgInstruction(DUP_X2);
147     }
148 
149     /**
150      * Generate the code required for doing the actual assignment. Here, this
151      * requires an array store.
152      * 
153      * @param output
154      *            the code emitter (basically an abstraction for producing the
155      *            .class file).
156      */
157 
158     public void codegenStore(CLEmitter output) {
159         if (type == Type.INT || type == Type.BOOLEAN || type == Type.CHAR) {
160             output.addNoArgInstruction(IASTORE);
161         } else if (!type.isPrimitive()) {
162             output.addNoArgInstruction(AASTORE);
163         }
164     }
165 
166     /**
167      * @inheritDoc
168      */
169 
170     public void writeToStdOut(PrettyPrinter p) {
171         p.println("<JArrayExpression>");
172         p.indentRight();
173         if (theArray != null) {
174             p.println("<TheArray>");
175             p.indentRight();
176             theArray.writeToStdOut(p);
177             p.indentLeft();
178             p.println("</TheArray>");
179         }
180         if (indexExpr != null) {
181             p.println("<IndexExpression>");
182             p.indentRight();
183             indexExpr.writeToStdOut(p);
184             p.indentLeft();
185             p.println("</IndexExpression>");
186         }
187         p.indentLeft();
188         p.println("</JArrayExpression>");
189     }
190 
191 }
192