001/* 002 * ============================================================================ 003 * Copyright © 2015 Square, Inc. 004 * Copyright for the modifications © 2018-2024 by Thomas Thrien. 005 * ============================================================================ 006 * 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020package org.tquadrat.foundation.javacomposer; 021 022import static org.apiguardian.api.API.Status.STABLE; 023 024import java.util.Map; 025 026import org.apiguardian.api.API; 027import org.tquadrat.foundation.annotation.ClassVersion; 028import org.tquadrat.foundation.javacomposer.internal.CodeBlockImpl; 029 030/** 031 * <p>{@summary The definition of a fragment for a {@code *.java} file, 032 * potentially containing declarations, statements, and documentation.} Code 033 * blocks are not necessarily well-formed Java code, and they are not 034 * validated. Implementations of this interface assume that {@code javac} will 035 * check correctness later!</p> 036 * <p>Code blocks do support placeholders like 037 * {@link java.text.Format}. 038 * Where 039 * {@link String#format(String, Object...) String.format()} 040 * uses percent {@code %} to reference target values, this class uses dollar 041 * sign {@code $} and has its own set of permitted placeholders:</p> 042 * <ul> 043 * <li>{@code $L} emits a <em>literal</em> value with no escaping. Arguments 044 * for literals may be strings, primitives, 045 * {@linkplain TypeSpec type declarations}, 046 * {@linkplain AnnotationSpec annotations} 047 * and even other code blocks.</li> 048 * <li>{@code $N} emits a <em>name</em>, using name collision avoidance where 049 * necessary. Arguments for names may be Strings (actually any 050 * {@linkplain CharSequence character sequence}), 051 * {@linkplain ParameterSpec parameters}, 052 * {@linkplain FieldSpec fields}, 053 * {@linkplain MethodSpec methods}, 054 * and 055 * {@linkplain TypeSpec types}.</li> 056 * <li>{@code $S} escapes the value as a <em>String</em>, wraps it with double 057 * quotes, and emits that. For example, {@code 6" sandwich} is emitted 058 * {@code "6\" sandwich"}.</li> 059 * <li>{@code $T} emits a <em>type</em> reference. Types will be imported if 060 * possible. Arguments for types may be 061 * {@linkplain Class classes}, 062 * {@linkplain javax.lang.model.type.TypeMirror type mirrors}, 063 * and 064 * {@linkplain javax.lang.model.element.Element elements}.</li> 065 * <li>{@code $$} emits a dollar sign.</li> 066 * <li>{@code $W} emits a space or a newline, depending on its position on the 067 * line. This prefers to wrap lines before 100 columns.</li> 068 * <li>{@code $Z} acts as a zero-width space. This prefers to wrap lines 069 * before 100 columns.</li> 070 * <li>{@code $>} increases the indentation level.</li> 071 * <li>{@code $<} decreases the indentation level.</li> 072 * <li>{@code $[} begins a statement. For multi-line statements, every line 073 * after the first line is double-indented.</li> 074 * <li>{@code $]} ends a statement.</li> 075 * </ul> 076 * 077 * @author Square,Inc. 078 * @modified Thomas Thrien - thomas.thrien@tquadrat.org 079 * @version $Id: CodeBlock.java 1085 2024-01-05 16:23:28Z tquadrat $ 080 * @since 0.0.5 081 * 082 * @UMLGraph.link 083 */ 084@ClassVersion( sourceVersion = "$Id: CodeBlock.java 1085 2024-01-05 16:23:28Z tquadrat $" ) 085@API( status = STABLE, since = "0.0.5" ) 086public sealed interface CodeBlock 087 permits CodeBlockImpl 088{ 089 /*---------------*\ 090 ====** Inner Classes **==================================================== 091 \*---------------*/ 092 /** 093 * The definition of a builder for a new instance of an implementation of 094 * {@link CodeBlock}. 095 * 096 * @author Square,Inc. 097 * @modified Thomas Thrien - thomas.thrien@tquadrat.org 098 * @version $Id: CodeBlock.java 1085 2024-01-05 16:23:28Z tquadrat $ 099 * @since 0.0.5 100 * 101 * @UMLGraph.link 102 */ 103 @SuppressWarnings( "InnerClassOfInterface" ) 104 @ClassVersion( sourceVersion = "$Id: CodeBlock.java 1085 2024-01-05 16:23:28Z tquadrat $" ) 105 @API( status = STABLE, since = "0.0.5" ) 106 public static interface Builder 107 { 108 /*---------*\ 109 ====** Methods **====================================================== 110 \*---------*/ 111 /** 112 * Adds a 113 * {@link CodeBlock} 114 * instance. 115 * 116 * @param codeBlock The code block. 117 * @return This {@code Builder} instance. 118 */ 119 public Builder add( final CodeBlock codeBlock ); 120 121 /** 122 * <p>{@summary Adds code with positional or relative arguments.}</p> 123 * <p>Relative arguments map 1:1 with the placeholders in the format 124 * string.</p> 125 * <p>Positional arguments use an index after the placeholder to 126 * identify which argument index to use. For example, for a literal to 127 * reference the 3<sup>rd</sup> argument, use {@code "$3L"} (1 based 128 * index).</p> 129 * <p>Mixing relative and positional arguments in a call to add is 130 * illegal and will result in an error.</p> 131 * 132 * @param format The format; may be empty. 133 * @param args The arguments. 134 * @return This {@code Builder} instance. 135 */ 136 public Builder add( final String format, final Object... args ); 137 138 /** 139 * <p>{@summary Adds code using named arguments.}</p> 140 * <p>Named arguments specify their name after the '$' followed by a 141 * colon {@code ":"} and the corresponding type character. Argument 142 * names consist of characters in {@code a-z, A-Z, 0-9, and _} and 143 * must start with a lowercase character.</p> 144 * <p>For example, to refer to the type 145 * {@link java.lang.Integer} 146 * with the argument name {@code clazz} use a format string containing 147 * {@code $clazz:T} and include the key {@code clazz} with value 148 * {@code java.lang.Integer.class} in the argument map.</p> 149 * 150 * @param format The format. 151 * @param args The arguments. 152 * @return This {@code Builder} instance. 153 */ 154 public Builder addNamed( final String format, final Map<String,?> args ); 155 156 /** 157 * <p>{@summary Adds a statement.}</p> 158 * <p>Do not use this method when the resulting code should be used 159 * as a field initializer. Use 160 * {@link #add(String, Object...)} 161 * instead.</p> 162 * 163 * @param format The format. 164 * @param args The arguments. 165 * @return This {@code Builder} instance. 166 * 167 * @see FieldSpec.Builder#initializer(CodeBlock) 168 */ 169 public Builder addStatement( final String format, final Object... args ); 170 171 /** 172 * Adds a static import. 173 * 174 * @param clazz The class. 175 * @param names The names of the elements from the given class that 176 * are to be imported. 177 * @return This {@code Builder} instance. 178 * 179 * @since 0.2.0 180 */ 181 @API( status = STABLE, since = "0.2.0" ) 182 public Builder addStaticImport( final Class<?> clazz, final String... names ); 183 184 /** 185 * Adds a static import. 186 * 187 * @param className The class. 188 * @param names The names of the elements from the given class that 189 * are to be imported. 190 * @return This {@code Builder} instance. 191 * 192 * @since 0.2.0 193 */ 194 @API( status = STABLE, since = "0.2.0" ) 195 public Builder addStaticImport( final ClassName className, final String... names ); 196 197 /** 198 * Adds a static import for the given {@code enum} value. 199 * 200 * @param constant The {@code enum} value. 201 * @return This {@code Builder} instance. 202 * 203 * @since 0.2.0 204 */ 205 @API( status = STABLE, since = "0.2.0" ) 206 public Builder addStaticImport( final Enum<?> constant ); 207 208 /** 209 * Starts a control flow construct. 210 * 211 * @param controlFlow <p>The control flow construct and its code, such 212 * as {@code if (foo == 5)}.</p> 213 * <p>Shouldn't contain braces or newline characters.</p> 214 * @param args The arguments. 215 * @return This {@code Builder} instance. 216 * 217 * @see #endControlFlow() 218 * @see #endControlFlow(String, Object...) 219 * @see #nextControlFlow(String, Object...) 220 */ 221 public Builder beginControlFlow( final String controlFlow, final Object... args ); 222 223 /** 224 * Creates the 225 * {@link CodeBlock} 226 * from the added components. 227 * 228 * @return The new {@code CodeBlock} instance. 229 */ 230 public CodeBlock build(); 231 232 /** 233 * Ends a control flow construct that was previously begun with a call 234 * to 235 * {@link #beginControlFlow(String, Object...)}. 236 * 237 * @return This {@code Builder} instance. 238 */ 239 public Builder endControlFlow(); 240 241 /** 242 * <p>{@summary Ends a control flow construct that was previously 243 * started with a call to 244 * {@link #beginControlFlow(String,Object...)} 245 * or 246 * {@link #beginControlFlow(String,Object...)}.}</p> 247 * <p>This form is only used for {@code do/while} control flows.</p> 248 * 249 * @param controlFlow The optional control flow construct and its 250 * code, such as {@code while(foo == 20)}. 251 * @param args The arguments. 252 * @return This {@code Builder} instance. 253 */ 254 public Builder endControlFlow( final String controlFlow, final Object... args ); 255 256 /** 257 * Adds an indentation level to the code block. 258 * 259 * @return This {@code Builder} instance. 260 */ 261 public Builder indent(); 262 263 /** 264 * Checks whether the code block to build would be empty. 265 * 266 * @return {@code true} if the code block would be empty, 267 * {@code false} otherwise. 268 */ 269 public boolean isEmpty(); 270 271 /** 272 * Adds another control flow construct to an already existing one. 273 * 274 * @param controlFlow <p>The control flow construct and its code, such 275 * as {@code else if (foo == 10)}.</p> 276 * <p>Shouldn't contain braces or newline characters.</p> 277 * @param args The arguments. 278 * @return This {@code Builder} instance. 279 */ 280 public Builder nextControlFlow( final String controlFlow, final Object... args ); 281 282 /** 283 * Removes an indentation level from the code block. 284 * 285 * @return This {@code Builder} instance. 286 */ 287 public Builder unindent(); 288 } 289 // interface Builder 290 291 /*---------*\ 292 ====** Methods **========================================================== 293 \*---------*/ 294 /** 295 * {@inheritDoc} 296 */ 297 @Override 298 public boolean equals( final Object o ); 299 300 /** 301 * {@inheritDoc} 302 */ 303 @Override 304 public int hashCode(); 305 306 /** 307 * Checks whether this code block is empty. 308 * 309 * @return {@code true} if the code block is empty, {@code false} 310 * otherwise. 311 */ 312 public boolean isEmpty(); 313 314 /** 315 * <p>{@summary Joins this code block with the given code blocks into a 316 * single new {@code CodeBlock} instance, each separated by the given 317 * separator.}</p> 318 * <p>For example, joining "{@code String s}", 319 * "{@code Object o}" and "{@code int i}" using 320 * "{@code , }" as the separator would produce 321 * "{@code String s, Object o, int i}".</p> 322 * 323 * @param separator The separator. 324 * @param codeBlocks The code blocks to join with this one. 325 * @return The new code block. 326 */ 327 @API( status = STABLE, since = "0.2.0" ) 328 public CodeBlock join( final String separator, final CodeBlock... codeBlocks ); 329 330 /** 331 * <p>{@summary Joins this code block with the given code blocks into a 332 * single new {@code CodeBlock} instance, each separated by the given 333 * separator.} The given prefix will be prepended to the new 334 * {@code CodeBloc}, and the given suffix will be appended to it.</p> 335 * <p>For example, joining "{@code String s}", 336 * "{@code Object o}" and "{@code int i}" using 337 * "{@code , }" as the separator would produce 338 * "{@code String s, Object o, int i}".</p> 339 * 340 * @param separator The separator. 341 * @param prefix The prefix. 342 * @param suffix The suffix. 343 * @param codeBlocks The code blocks to join. 344 * @return The new code block. 345 */ 346 @API( status = STABLE, since = "0.2.0" ) 347 public CodeBlock join( final String separator, final String prefix, final String suffix, final CodeBlock... codeBlocks ); 348 349 /** 350 * Creates a new builder that is initialised with the components of this 351 * code block. 352 * 353 * @return The new builder. 354 */ 355 public Builder toBuilder(); 356 357 /** 358 * {@inheritDoc} 359 */ 360 @Override 361 public String toString(); 362} 363// interface CodeBlock 364 365/* 366 * End of File 367 */