1 /*
2  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.codemodel.internal;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Collections;
31 
32 /**
33  * A block of Java code, which may contain statements and local declarations.
34  *
35  * <p>
36  * {@link JBlock} contains a large number of factory methods that creates new
37  * statements/declarations. Those newly created statements/declarations are
38  * inserted into the {@link #pos() "current position"}. The position advances
39  * one every time you add a new instruction.
40  */
41 public final class JBlock implements JGenerable, JStatement {
42 
43     /**
44      * Declarations and statements contained in this block.
45      * Either {@link JStatement} or {@link JDeclaration}.
46      */
47     private final List<Object> content = new ArrayList<Object>();
48 
49     /**
50      * Whether or not this block must be braced and indented
51      */
52     private boolean bracesRequired = true;
53     private boolean indentRequired = true;
54 
55     /**
56      * Current position.
57      */
58     private int pos;
59 
JBlock()60     public JBlock() {
61         this(true,true);
62     }
63 
JBlock(boolean bracesRequired, boolean indentRequired)64     public JBlock(boolean bracesRequired, boolean indentRequired) {
65         this.bracesRequired = bracesRequired;
66         this.indentRequired = indentRequired;
67     }
68 
69     /**
70      * Returns a read-only view of {@link JStatement}s and {@link JDeclaration}
71      * in this block.
72      */
getContents()73     public List<Object> getContents() {
74         return Collections.unmodifiableList(content);
75     }
76 
insert( T statementOrDeclaration )77     private <T> T insert( T statementOrDeclaration ) {
78         content.add(pos,statementOrDeclaration);
79         pos++;
80         return statementOrDeclaration;
81     }
82 
83     /**
84      * Gets the current position to which new statements will be inserted.
85      *
86      * For example if the value is 0, newly created instructions will be
87      * inserted at the very beginning of the block.
88      *
89      * @see #pos(int)
90      */
pos()91     public int pos() {
92         return pos;
93     }
94 
95     /**
96      * Sets the current position.
97      *
98      * @return
99      *      the old value of the current position.
100      * @throws IllegalArgumentException
101      *      if the new position value is illegal.
102      *
103      * @see #pos()
104      */
pos(int newPos)105     public int pos(int newPos) {
106         int r = pos;
107         if(newPos>content.size() || newPos<0)
108             throw new IllegalArgumentException();
109         pos = newPos;
110 
111         return r;
112     }
113 
114     /**
115      * Returns true if this block is empty and does not contain
116      * any statement.
117      */
isEmpty()118     public boolean isEmpty() {
119         return content.isEmpty();
120     }
121 
122     /**
123      * Adds a local variable declaration to this block
124      *
125      * @param type
126      *        JType of the variable
127      *
128      * @param name
129      *        Name of the variable
130      *
131      * @return Newly generated JVar
132      */
decl(JType type, String name)133     public JVar decl(JType type, String name) {
134         return decl(JMod.NONE, type, name, null);
135     }
136 
137     /**
138      * Adds a local variable declaration to this block
139      *
140      * @param type
141      *        JType of the variable
142      *
143      * @param name
144      *        Name of the variable
145      *
146      * @param init
147      *        Initialization expression for this variable.  May be null.
148      *
149      * @return Newly generated JVar
150      */
decl(JType type, String name, JExpression init)151     public JVar decl(JType type, String name, JExpression init) {
152         return decl(JMod.NONE, type, name, init);
153     }
154 
155     /**
156      * Adds a local variable declaration to this block
157      *
158      * @param mods
159      *        Modifiers for the variable
160      *
161      * @param type
162      *        JType of the variable
163      *
164      * @param name
165      *        Name of the variable
166      *
167      * @param init
168      *        Initialization expression for this variable.  May be null.
169      *
170      * @return Newly generated JVar
171      */
decl(int mods, JType type, String name, JExpression init)172     public JVar decl(int mods, JType type, String name, JExpression init) {
173         JVar v = new JVar(JMods.forVar(mods), type, name, init);
174         insert(v);
175         bracesRequired = true;
176         indentRequired = true;
177         return v;
178     }
179 
180     /**
181      * Creates an assignment statement and adds it to this block.
182      *
183      * @param lhs
184      *        Assignable variable or field for left hand side of expression
185      *
186      * @param exp
187      *        Right hand side expression
188      */
assign(JAssignmentTarget lhs, JExpression exp)189     public JBlock assign(JAssignmentTarget lhs, JExpression exp) {
190         insert(new JAssignment(lhs, exp));
191         return this;
192     }
193 
assignPlus(JAssignmentTarget lhs, JExpression exp)194     public JBlock assignPlus(JAssignmentTarget lhs, JExpression exp) {
195         insert(new JAssignment(lhs, exp, "+"));
196         return this;
197     }
198 
199     /**
200      * Creates an invocation statement and adds it to this block.
201      *
202      * @param expr
203      *        JExpression evaluating to the class or object upon which
204      *        the named method will be invoked
205      *
206      * @param method
207      *        Name of method to invoke
208      *
209      * @return Newly generated JInvocation
210      */
invoke(JExpression expr, String method)211     public JInvocation invoke(JExpression expr, String method) {
212         JInvocation i = new JInvocation(expr, method);
213         insert(i);
214         return i;
215     }
216 
217     /**
218      * Creates an invocation statement and adds it to this block.
219      *
220      * @param expr
221      *        JExpression evaluating to the class or object upon which
222      *        the method will be invoked
223      *
224      * @param method
225      *        JMethod to invoke
226      *
227      * @return Newly generated JInvocation
228      */
invoke(JExpression expr, JMethod method)229     public JInvocation invoke(JExpression expr, JMethod method) {
230         return insert(new JInvocation(expr, method));
231     }
232 
233     /**
234      * Creates a static invocation statement.
235      */
staticInvoke(JClass type, String method)236     public JInvocation staticInvoke(JClass type, String method) {
237         return insert(new JInvocation(type, method));
238     }
239 
240     /**
241      * Creates an invocation statement and adds it to this block.
242      *
243      * @param method
244      *        Name of method to invoke
245      *
246      * @return Newly generated JInvocation
247      */
invoke(String method)248     public JInvocation invoke(String method) {
249         return insert(new JInvocation((JExpression)null, method));
250     }
251 
252     /**
253      * Creates an invocation statement and adds it to this block.
254      *
255      * @param method
256      *        JMethod to invoke
257      *
258      * @return Newly generated JInvocation
259      */
invoke(JMethod method)260     public JInvocation invoke(JMethod method) {
261         return insert(new JInvocation((JExpression)null, method));
262     }
263 
264     /**
265      * Adds a statement to this block
266      *
267      * @param s
268      *        JStatement to be added
269      *
270      * @return This block
271      */
add(JStatement s)272     public JBlock add(JStatement s) { // ## Needed?
273         insert(s);
274         return this;
275     }
276 
277     /**
278      * Create an If statement and add it to this block
279      *
280      * @param expr
281      *        JExpression to be tested to determine branching
282      *
283      * @return Newly generated conditional statement
284      */
_if(JExpression expr)285     public JConditional _if(JExpression expr) {
286         return insert(new JConditional(expr));
287     }
288 
289     /**
290      * Create a For statement and add it to this block
291      *
292      * @return Newly generated For statement
293      */
_for()294     public JForLoop _for() {
295         return insert(new JForLoop());
296     }
297 
298     /**
299      * Create a While statement and add it to this block
300      *
301      * @return Newly generated While statement
302      */
_while(JExpression test)303     public JWhileLoop _while(JExpression test) {
304         return insert(new JWhileLoop(test));
305     }
306 
307     /**
308      * Create a switch/case statement and add it to this block
309      */
_switch(JExpression test)310     public JSwitch _switch(JExpression test) {
311         return insert(new JSwitch(test));
312     }
313 
314     /**
315      * Create a Do statement and add it to this block
316      *
317      * @return Newly generated Do statement
318      */
_do(JExpression test)319     public JDoLoop _do(JExpression test) {
320         return insert(new JDoLoop(test));
321     }
322 
323     /**
324      * Create a Try statement and add it to this block
325      *
326      * @return Newly generated Try statement
327      */
_try()328     public JTryBlock _try() {
329         return insert(new JTryBlock());
330     }
331 
332     /**
333      * Create a return statement and add it to this block
334      */
_return()335     public void _return() {
336         insert(new JReturn(null));
337     }
338 
339     /**
340      * Create a return statement and add it to this block
341      */
_return(JExpression exp)342     public void _return(JExpression exp) {
343         insert(new JReturn(exp));
344     }
345 
346     /**
347      * Create a throw statement and add it to this block
348      */
_throw(JExpression exp)349     public void _throw(JExpression exp) {
350         insert(new JThrow(exp));
351     }
352 
353     /**
354      * Create a break statement and add it to this block
355      */
_break()356     public void _break() {
357         _break(null);
358     }
359 
_break(JLabel label)360     public void _break(JLabel label) {
361         insert(new JBreak(label));
362     }
363 
364     /**
365      * Create a label, which can be referenced from
366      * <code>continue</code> and <code>break</code> statements.
367      */
label(String name)368     public JLabel label(String name) {
369         JLabel l = new JLabel(name);
370         insert(l);
371         return l;
372     }
373 
374     /**
375      * Create a continue statement and add it to this block
376      */
_continue(JLabel label)377     public void _continue(JLabel label) {
378         insert(new JContinue(label));
379     }
380 
_continue()381     public void _continue() {
382         _continue(null);
383     }
384 
385     /**
386      * Create a sub-block and add it to this block
387      */
block()388     public JBlock block() {
389         JBlock b = new JBlock();
390         b.bracesRequired = false;
391         b.indentRequired = false;
392         return insert(b);
393     }
394 
395     /**
396      * Creates a "literal" statement directly.
397      *
398      * <p>
399      * Specified string is printed as-is.
400      * This is useful as a short-cut.
401      *
402      * <p>
403      * For example, you can invoke this method as:
404      * <code>directStatement("a=b+c;")</code>.
405      */
directStatement(final String source)406     public JStatement directStatement(final String source) {
407         JStatement s = new JStatement() {
408             public void state(JFormatter f) {
409                 f.p(source).nl();
410             }
411         };
412         add(s);
413         return s;
414     }
415 
generate(JFormatter f)416     public void generate(JFormatter f) {
417         if (bracesRequired)
418             f.p('{').nl();
419         if (indentRequired)
420             f.i();
421         generateBody(f);
422         if (indentRequired)
423             f.o();
424         if (bracesRequired)
425             f.p('}');
426     }
427 
generateBody(JFormatter f)428     void generateBody(JFormatter f) {
429         for (Object o : content) {
430             if (o instanceof JDeclaration)
431                 f.d((JDeclaration) o);
432             else
433                 f.s((JStatement) o);
434         }
435     }
436 
437     /**
438      * Creates an enhanced For statement based on j2se 1.5 JLS
439      * and add it to this block
440      *
441      * @return Newly generated enhanced For statement per j2se 1.5
442      * specification
443     */
forEach(JType varType, String name, JExpression collection)444     public JForEach forEach(JType varType, String name, JExpression collection) {
445         return insert(new JForEach( varType, name, collection));
446 
447     }
state(JFormatter f)448     public void state(JFormatter f) {
449         f.g(this);
450         if (bracesRequired)
451             f.nl();
452     }
453 
454 }
455