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 
  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 }