001/*
002 * ============================================================================
003 * Copyright © 2002-2024 by Thomas Thrien.
004 * All Rights Reserved.
005 * ============================================================================
006 *
007 * Licensed to the public under the agreements of the GNU Lesser General Public
008 * License, version 3.0 (the "License"). You may obtain a copy of the License at
009 *
010 *      http://www.gnu.org/licenses/lgpl.html
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015 * License for the specific language governing permissions and limitations
016 * under the License.
017 */
018
019package org.tquadrat.foundation.javacomposer;
020
021import static org.apiguardian.api.API.Status.STABLE;
022
023import javax.lang.model.element.Modifier;
024import java.lang.reflect.Type;
025
026import org.apiguardian.api.API;
027import org.tquadrat.foundation.annotation.ClassVersion;
028import org.tquadrat.foundation.javacomposer.internal.LambdaSpecImpl;
029
030/**
031 *  <p>{@summary The specification for a generated lambda construct.}</p>
032 *  <h2>Parameters and Types</h2>
033 *  <p>When adding more than one parameter, all of them must have a specified
034 *  type or none of them may have one, leaving the compiler to infer the type.
035 *  As
036 *  {@link JavaComposer#parameterBuilder(Type, CharSequence, Modifier...) paramterBuilder()}
037 *  does require a type, we take
038 *  {@link Primitives#VOID}
039 *  instead of a concrete type if we want to get the type being inferred.</p>
040 *  <h2>Formatting</h2>
041 *  <p>Basically, a lambda expression has two different formats, one without
042 *  curly braces</p>
043 *  <pre><code>  a -&gt; modify( a )</code></pre>
044 *  <p>and the other with with curly braces, requiring a return statement:</p>
045 *  <pre><code>  a -&gt;
046 *  {
047 *      modify( a );
048 *      return a.result;
049 *  }</code></pre>
050 *  <p>The body of the second form usually has more than one statement.</p>
051 *  <p>JavaComposer emits the first form when only one of the methods</p>
052 *  <ul>
053 *      <li>{@link LambdaSpec.Builder#addCode(String, Object...)}</li>
054 *      <li>{@link LambdaSpec.Builder#addCode(CodeBlock)}</li>
055 *  </ul>
056 *  <p>is called only once on the builder instance. The second form is forced,
057 *  when one of the methods above is called again, or when one of the
058 *  methods</p>
059 *  <ul>
060 *      <li>{@link LambdaSpec.Builder#addComment(String, Object...)}</li>
061 *      <li>{@link LambdaSpec.Builder#addStatement(String, Object...)}</li>
062 *      <li>{@link LambdaSpec.Builder#beginControlFlow(String, Object...)}</li>
063 *      <li>{@link LambdaSpec.Builder#endControlFlow()}</li>
064 *      <li>{@link LambdaSpec.Builder#endControlFlow(String, Object...)}</li>
065 *      <li>{@link LambdaSpec.Builder#nextControlFlow(String, Object...)}</li>
066 *  </ul>
067 *  <p>is called.</p>
068 *  <p>There is no validation on the code; this means it is in the caller's
069 *  responsibility to ensure that there is a {@code return} statement in the
070 *  second case.</p>
071 *
072 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
073 *  @version $Id: LambdaSpec.java 1085 2024-01-05 16:23:28Z tquadrat $
074 *  @since 0.0.5
075 *
076 *  @UMLGraph.link
077 */
078@ClassVersion( sourceVersion = "$Id: LambdaSpec.java 1085 2024-01-05 16:23:28Z tquadrat $" )
079@API( status = STABLE, since = "0.0.5" )
080public sealed interface LambdaSpec
081    permits LambdaSpecImpl
082{
083        /*---------------*\
084    ====** Inner Classes **====================================================
085        \*---------------*/
086    /**
087     *  The builder for an instance of
088     *  {@link LambdaSpec}
089     *
090     *  @extauthor  Thomas Thrien - thomas.thrien@tquadrat.org
091     *  @version $Id: LambdaSpec.java 1085 2024-01-05 16:23:28Z tquadrat $
092     *  @since 0.0.5
093     *
094     *  @UMLGraph.link
095     */
096    @SuppressWarnings( "InnerClassOfInterface" )
097    @ClassVersion( sourceVersion = "$Id: LambdaSpec.java 1085 2024-01-05 16:23:28Z tquadrat $" )
098    @API( status = STABLE, since = "0.0.5" )
099    public static sealed interface Builder
100        permits LambdaSpecImpl.BuilderImpl
101    {
102            /*---------*\
103        ====** Methods **======================================================
104            \*---------*/
105        /**
106         *  <p>{@summary Adds code for the lambda body.}</p>
107         *  <p>If only this method is called only once to add code to the
108         *  lambda body, the short, single line form for the lambda expression
109         *  will be emitted. That this will result in valid code requires that
110         *  the given code block has an appropriate contents.</p>
111         *
112         *  @param  codeBlock   The code.
113         *  @return This {@code Builder} instance.
114         */
115        public Builder addCode( final CodeBlock codeBlock );
116
117        /**
118         *  <p>{@summary Adds code for the lambda body.}</p>
119         *  <p>If only this method is called only once to add code to the
120         *  lambda body, the short, single line form for the lambda expression
121         *  will be emitted.</p>
122         *
123         *  @param  format  The format.
124         *  @param  args    The arguments.
125         *  @return This {@code Builder} instance.
126         */
127        public Builder addCode( final String format, final Object... args );
128
129        /**
130         *  <p>{@summary Adds a comment for the lambda body.}</p>
131         *  <p>A call to this method forces the multi-line emit format for the
132         *  lambda expression.</p>
133         *
134         *  @param  format  The format.
135         *  @param  args    The arguments.
136         *  @return This {@code Builder} instance.
137         */
138        public Builder addComment( final String format, final Object... args );
139
140        /**
141         *  <p>{@summary Adds a parameter for the lambda.}</p>
142         *  <p>The type of the parameter is inferred.</p>
143         *
144         *  @param  name    The name of the parameter.
145         *  @return This {@code Builder} instance.
146         */
147        public Builder addParameter( final String name );
148
149        /**
150         *  Adds a parameter for the lambda. Only type and name of the given
151         *  parameter are considered, annotations or modifiers will be ignored.
152         *
153         *  @param  parameterSpec   The parameter.
154         *  @return This {@code Builder} instance.
155         */
156        public Builder addParameter( final ParameterSpec parameterSpec );
157
158        /**
159         *  Adds a parameter for the lambda.
160         *
161         *  @param  type    The type of the parameter.
162         *  @param  name    The name of the parameter.
163         *  @return This {@code Builder} instance.
164         */
165        public Builder addParameter( final Type type, final String name );
166
167        /**
168         *  Adds a parameter for the lambda.
169         *
170         *  @param  type    The type of the parameter.
171         *  @param  name    The name of the parameter.
172         *  @return This {@code Builder} instance.
173         */
174        public Builder addParameter( final TypeName type, final String name );
175
176        /**
177         *  Adds parameters for the lambda. Only type and name of the given
178         *  parameters are considered, annotations or modifiers will be
179         *  ignored.
180         *
181         *  @param  parameterSpecs  The parameters.
182         *  @return This {@code Builder} instance.
183         */
184        public Builder addParameters( final Iterable<? extends ParameterSpec> parameterSpecs );
185
186        /**
187         *  <p>{@summary Adds a statement to the code for the lambda body.}</p>
188         *  <p>A call to this method forces the multi-line emit format for the
189         *  lambda expression.</p>
190         *
191         *  @param  format  The format.
192         *  @param  args    The arguments.
193         *  @return This {@code Builder} instance.
194         */
195        public Builder addStatement( final String format, final Object... args );
196
197        /**
198         *  <p>{@summary Adds the begin of a control flow for the lambda
199         *  body.}</p>
200         *  <p>A call to this method forces the multi-line emit format for the
201         *  lambda expression.</p>
202         *
203         *  @param  controlFlow The control flow construct and its code, such
204         *      as &quot;{@code if (foo == 5)}&quot;; it should not contain
205         *      braces or newline characters.
206         *  @param  args    The arguments.
207         *  @return This {@code Builder} instance.
208         *
209         *  @see #endControlFlow()
210         *  @see #endControlFlow(String, Object...)
211         *  @see #nextControlFlow(String, Object...)
212         */
213        public Builder beginControlFlow( final String controlFlow, final Object... args );
214
215        /**
216         *  Creates a new
217         *  {@link LambdaSpec}
218         *  instance from the components that have been added to this builder.
219         *
220         *  @return The {@code MethodSpec} instance.
221         */
222        public LambdaSpec build();
223
224        /**
225         *  <p>{@summary Ends the current control flow for the lambda
226         *  body.}</p>
227         *  <p>A call to this method forces the multi-line emit format for the
228         *  lambda expression.</p>
229         *
230         *  @return This {@code Builder} instance.
231         *
232         *  @see #beginControlFlow(String, Object...)
233         *  @see #endControlFlow(String, Object...)
234         *  @see #nextControlFlow(String, Object...)
235         */
236        public Builder endControlFlow();
237
238        /**
239         *  <p>{@summary Ends the current control flow for the lambda body;
240         *  this version is only used for {@code do-while} constructs.}</p>
241         *  <p>A call to this method forces the multi-line emit format for the
242         *  lambda expression.</p>
243         *
244         *  @param  controlFlow The optional control flow construct and its
245         *      code, such as &quot;{@code while(foo == 20)}&quot;; it should
246         *      not contain braces or newline characters.
247         *  @param  args    The arguments.
248         *  @return This {@code Builder} instance.
249         *
250         *  @see #beginControlFlow(String, Object...)
251         *  @see #endControlFlow()
252         */
253        public Builder endControlFlow( final String controlFlow, final Object... args );
254
255        /**
256         *  <p>{@summary Begins another control flow for the lambda body.}</p>
257         *  <p>A call to this method forces the multi-line emit format for the
258         *  lambda expression.</p>
259         *
260         *  @param  controlFlow The control flow construct and its code, such
261         *      as &quot;{@code else if (foo == 10)}&quot;; it should not
262         *      contain braces or newline characters.
263         *  @param  args    The arguments.
264         *  @return This {@code Builder} instance.
265         *
266         *  @see #beginControlFlow(String, Object...)
267         *  @see #endControlFlow()
268         */
269        public Builder nextControlFlow( final String controlFlow, final Object... args );
270    }
271    //  interface Builder
272
273        /*---------*\
274    ====** Methods **==========================================================
275        \*---------*/
276    /**
277     *  {@inheritDoc}
278     */
279    @Override
280    public boolean equals( final Object o );
281
282    /**
283     *  {@inheritDoc}
284     */
285    @Override
286    public int hashCode();
287
288    /**
289     *  Creates a new builder that is initialised with the components of this
290     *  lambda.
291     *
292     *  @return The new builder.
293     */
294    public Builder toBuilder();
295
296    /**
297     *  {@inheritDoc}
298     */
299    @Override
300    public String toString();
301}
302//  class LambdaSpec
303
304/*
305 *  End of File
306 */