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}