001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2025–2026 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 * 046 * @see Domain 047 */ 048public interface PrimordialDomain { 049 050 /** 051 * Returns the (non-{@code null}, determinate) {@link DeclaredType} representing the <a 052 * href="https://docs.oracle.com/en/java/javase/25/docs/api/java.compiler/javax/lang/model/element/TypeElement.html#prototypicaltype"><dfn>prototypical 053 * type</dfn></a> of {@link Object java.lang.Object}. 054 * 055 * <p>Implementations of this method must not return {@code null}.</p> 056 * 057 * <p>{@link DeclaredType} instances returned by implementations of this method must return {@link TypeKind#DECLARED} 058 * from their {@link TypeMirror#getKind()} method.</p> 059 * 060 * @return the {@link DeclaredType} representing the <dfn>prototypical type</dfn> of {@link Object java.lang.Object}; 061 * never {@code null} 062 */ 063 public DeclaredType javaLangObjectType(); 064 065 /** 066 * Semantically locks an opaque lock used to serialize symbol completion, and returns it in the form of an {@link 067 * Unlockable}. 068 * 069 * <p>Implementations of this method must not return {@code null}.</p> 070 * 071 * @return an {@link Unlockable} in a semantically locked state; never {@code null} 072 * 073 * @see SymbolCompletionLock 074 * 075 * @see Unlockable#close() 076 */ 077 public Unlockable lock(); 078 079 /** 080 * Returns a (non-{@code null}, determinate) {@link NoType} representing the supplied {@link TypeKind}, provided it is 081 * either {@link TypeKind#NONE} or {@link TypeKind#VOID}. 082 * 083 * <p>Implementations of this method must not return {@code null}.</p> 084 * 085 * @param kind a {@link TypeKind}; must be either {@link TypeKind#NONE} or {@link TypeKind#VOID} 086 * 087 * @return a {@link NoType} representing the supplied {@link TypeKind}; never {@code null} 088 * 089 * @exception NullPointerException if {@code kind} is {@code null} 090 * 091 * @exception IllegalArgumentException if {@code kind} is neither {@link TypeKind#NONE} nor {@link TypeKind#VOID} 092 * 093 * @see javax.lang.model.util.Types#getNoType(TypeKind) 094 */ 095 public NoType noType(final TypeKind kind); 096 097 /** 098 * Returns a (non-{@code null}, determinate) {@link NullType} representing the null type. 099 * 100 * <p>Implementations of this method must not return {@code null}.</p> 101 * 102 * @return a {@link NullType} representing the null type; never {@code null} 103 * 104 * @see javax.lang.model.util.Types#getNullType() 105 */ 106 public NullType nullType(); 107 108 /** 109 * A convenience method that converts the supplied {@link CharSequence}, which is often a {@link Name}, into a {@link 110 * String}, and returns the conversion, {@linkplain #lock() locking} when appropriate to serialize symbol completion. 111 * 112 * <p>The default implementation of this method may return {@code null} if the supplied {@code name} is {@code 113 * null}.</p> 114 * 115 * <p>In many implementations of {@link PrimordialDomain}s, converting a {@link Name} to a {@link String} can cause 116 * problems if symbol completion is taking place concurrently and the symbol completion lock is not held. This method 117 * helps avoid those problems.</p> 118 * 119 * <p>Overriding this method is not normally needed.</p> 120 * 121 * @param name the {@link CharSequence} to convert; may be {@code null} in which case {@code null} will be returned 122 * 123 * @return a {@link String}, or {@code null} if {@code name} was {@code null} 124 * 125 * @see #lock() 126 * 127 * @see Name 128 */ 129 @SuppressWarnings("try") 130 public default String toString(final CharSequence name) { 131 return switch (name) { 132 case null -> null; 133 case String s -> s; 134 case StringName sn -> sn.value(); 135 case SyntheticName sn -> sn.toString(); 136 case Name n -> { 137 try (var lock = this.lock()) { 138 yield n.toString(); 139 } 140 } 141 default -> name.toString(); 142 }; 143 } 144 145}