1/*
2 * Copyright (c) 1997, 2012, 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
26package com.sun.codemodel.internal;
27
28import java.util.ArrayList;
29import java.util.List;
30import 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 */
41public 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
60    public JBlock() {
61        this(true,true);
62    }
63
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     */
73    public List<Object> getContents() {
74        return Collections.unmodifiableList(content);
75    }
76
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     */
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     */
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     */
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     */
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     */
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     */
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     */
189    public JBlock assign(JAssignmentTarget lhs, JExpression exp) {
190        insert(new JAssignment(lhs, exp));
191        return this;
192    }
193
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
328    public JTryBlock _try() {
329        return insert(new JTryBlock());
330    }
331
332    /**
333     * Create a return statement and add it to this block
334     */
335    public void _return() {
336        insert(new JReturn(null));
337    }
338
339    /**
340     * Create a return statement and add it to this block
341     */
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     */
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     */
356    public void _break() {
357        _break(null);
358    }
359
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     */
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     */
377    public void _continue(JLabel label) {
378        insert(new JContinue(label));
379    }
380
381    public void _continue() {
382        _continue(null);
383    }
384
385    /**
386     * Create a sub-block and add it to this block
387     */
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     */
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
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
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    */
444    public JForEach forEach(JType varType, String name, JExpression collection) {
445        return insert(new JForEach( varType, name, collection));
446
447    }
448    public void state(JFormatter f) {
449        f.g(this);
450        if (bracesRequired)
451            f.nl();
452    }
453
454}
455