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 }