001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2025 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
006 * the License. You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
012 * specific language governing permissions and limitations under the License.
013 */
014package org.microbean.construct;
015
016import javax.lang.model.element.Name;
017
018import javax.lang.model.type.DeclaredType;
019import javax.lang.model.type.NoType;
020import javax.lang.model.type.NullType;
021import javax.lang.model.type.TypeKind;
022import javax.lang.model.type.TypeMirror;
023
024import org.microbean.construct.element.StringName;
025import org.microbean.construct.element.SyntheticName;
026
027/**
028 * A view of an underlying domain of valid Java constructs that exposes {@linkplain #nullType() the null type}, various
029 * kinds of {@linkplain #noType(TypeKind) pseudo-types}, the {@linkplain #javaLangObjectType() prototypical
030 * <code>java.lang.Object</code> type}, and the ability to {@linkplain #lock() globally lock for symbol completion if
031 * needed}.
032 *
033 * <p>{@link PrimordialDomain}s are primordial because they expose the "first principles" constructs needed to compose
034 * other constructs.</p>
035 *
036 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
037 *
038 * @see #javaLangObjectType()
039 *
040 * @see #lock()
041 *
042 * @see #noType(TypeKind)
043 *
044 * @see #nullType()
045 */
046public interface PrimordialDomain {
047
048  /**
049   * Returns the (non-{@code null}, determinate) {@link DeclaredType} representing the <a
050   * href="https://docs.oracle.com/en/java/javase/25/docs/api/java.compiler/javax/lang/model/element/TypeElement.html#prototypicaltype"><dfn>prototypical
051   * type</dfn></a> of {@link Object java.lang.Object}.
052   *
053   * <p>Implementations of this method must not return {@code null}.</p>
054   *
055   * <p>{@link DeclaredType} instances returned by implementations of this method must return {@link TypeKind#DECLARED}
056   * from their {@link TypeMirror#getKind()} method.</p>
057   *
058   * @return the {@link DeclaredType} representing the <dfn>prototypical type</dfn> of {@link Object java.lang.Object};
059   * never {@code null}
060   */
061  public DeclaredType javaLangObjectType();
062
063  /**
064   * Semantically locks an opaque lock used to serialize symbol completion, and returns it in the form of an {@link
065   * Unlockable}.
066   *
067   * <p>Implementations of this method must not return {@code null}.</p>
068   *
069   * @return an {@link Unlockable} in a semantically locked state; never {@code null}
070   *
071   * @see SymbolCompletionLock
072   *
073   * @see Unlockable#close()
074   */
075  public Unlockable lock();
076
077  /**
078   * Returns a (non-{@code null}, determinate) {@link NoType} representing the supplied {@link TypeKind}, provided it is
079   * either {@link TypeKind#NONE} or {@link TypeKind#VOID}.
080   *
081   * <p>Implementations of this method must not return {@code null}.</p>
082   *
083   * @param kind a {@link TypeKind}; must be either {@link TypeKind#NONE} or {@link TypeKind#VOID}
084   *
085   * @return a {@link NoType} representing the supplied {@link TypeKind}; never {@code null}
086   *
087   * @exception NullPointerException if {@code kind} is {@code null}
088   *
089   * @exception IllegalArgumentException if {@code kind} is neither {@link TypeKind#NONE} nor {@link TypeKind#VOID}
090   *
091   * @see javax.lang.model.util.Types#getNoType(TypeKind)
092   */
093  public NoType noType(final TypeKind kind);
094
095  /**
096   * Returns a (non-{@code null}, determinate) {@link NullType} representing the null type.
097   *
098   * <p>Implementations of thsi method must not return {@code null}.</p>
099   *
100   * @return a {@link NullType} representing the null type; never {@code null}
101   *
102   * @see javax.lang.model.util.Types#getNullType()
103   */
104  public NullType nullType();
105
106  /**
107   * A convenience method that converts the supplied {@link CharSequence}, which is often a {@link Name}, into a {@link
108   * String}, and returns the conversion, {@linkplain #lock() locking} when appropriate to serialize symbol completion.
109   *
110   * <p>The default implementation of this method may return {@code null} if the supplied {@code name} is {@code
111   * null}.</p>
112   *
113   * <p>In many implementations of domains, converting a {@link Name} to a {@link String} can cause problems if symbol
114   * completion is taking place concurrently and the symbol completion lock is not held. This method helps avoid those
115   * problems.</p>
116   *
117   * <p>Overriding this method is not normally needed.</p>
118   *
119   * @param name the {@link CharSequence} to convert; may be {@code null} in which case {@code null} will be returned
120   *
121   * @return a {@link String}, or {@code null} if {@code name} was {@code null}
122   *
123   * @see #lock()
124   *
125   * @see Name
126   */
127  @SuppressWarnings("try")
128  public default String toString(final CharSequence name) {
129    return switch (name) {
130    case null -> null;
131    case String s -> s;
132    case StringName sn -> sn.value();
133    case SyntheticName sn -> sn.toString();
134    case Name n -> {
135      try (var lock = this.lock()) {
136        yield n.toString();
137      }
138    }
139    default -> name.toString();
140    };
141  }
142  
143}