1 package java.lang.reflect.code;
  2 
  3 import java.lang.reflect.code.type.TypeElementFactory;
  4 import java.util.List;
  5 import java.util.stream.Collectors;
  6 
  7 /**
  8  * A type, that defines a set of values.
  9  * <p>
 10  * A type can be assigned to a {@link Value value} in a code model,
 11  * and implies the value is a member of the type's set.
 12  * <p>
 13  * The {@code equals} method should be used to check if two type elements
 14  * are equal to each other.
 15  * @apiNote
 16  * Code model types enable reasoning statically about a code model,
 17  * approximating run time behaviour.
 18  */
 19 public non-sealed interface TypeElement extends CodeItem {
 20     // @@@ Common useful methods generally associated with properties of a type
 21     // e.g., arguments, is an array etc. (dimensions)
 22 
 23     /**
 24      * A type element's externalized content in structured symbolic form.
 25      * <p>
 26      * A {@link TypeElement type element} can be constructed from an externalized type element
 27      * using a {@link TypeElementFactory}.
 28      *
 29      * @param identifier the externalized type's identifier
 30      * @param arguments  the externalized type's arguments
 31      */
 32     record ExternalizedTypeElement(String identifier, List<ExternalizedTypeElement> arguments) {
 33 
 34         /**
 35          * {@inheritDoc}
 36          */
 37         public ExternalizedTypeElement {
 38             arguments = List.copyOf(arguments);
 39         }
 40 
 41         @Override
 42         public String toString() {
 43             return toString(this);
 44         }
 45 
 46         static String toString(ExternalizedTypeElement t) {
 47             if (t.arguments.isEmpty()) {
 48                 return t.identifier;
 49             }
 50 
 51             // Unpack array-like identifier [+
 52             int dimensions = 0;
 53             if (t.arguments.size() == 1) {
 54                 dimensions = dimensions(t.identifier);
 55                 if (dimensions > 0) {
 56                     t = t.arguments.getFirst();
 57                 }
 58             }
 59 
 60             StringBuilder s = new StringBuilder();
 61             s.append(t.identifier);
 62             if (!t.arguments.isEmpty()) {
 63                 String args = t.arguments.stream()
 64                         .map(Object::toString)
 65                         .collect(Collectors.joining(", ", "<", ">"));
 66                 s.append(args);
 67             }
 68 
 69             // Write out array-like syntax at end []+
 70             if (dimensions > 0) {
 71                 s.append("[]".repeat(dimensions));
 72             }
 73 
 74             return s.toString();
 75         }
 76 
 77         static int dimensions(String identifier) {
 78             if (!identifier.isEmpty() && identifier.charAt(0) == '[') {
 79                 for (int i = 1; i < identifier.length(); i++) {
 80                     if (identifier.charAt(i) != '[') {
 81                         return 0;
 82                     }
 83                 }
 84                 return identifier.length();
 85             } else {
 86                 return 0;
 87             }
 88         }
 89 
 90         // Factories
 91 
 92         /**
 93          * Parses a string as an externalized type element.
 94          * <p>
 95          * For any given externalized type element, {@code te}, the following
 96          * expression returns {@code true}.
 97          * {@snippet lang=java
 98          * te.equals(ExternalizedTypeElement.ofString(te.toString()));
 99          * }
100          * @param s the string
101          * @return the externalized code type.
102          */
103         // Copied code in jdk.compiler module throws UOE
104         public static ExternalizedTypeElement ofString(String s) {
105 /*__throw new UnsupportedOperationException();__*/        return java.lang.reflect.code.parser.impl.DescParser.parseExTypeElem(s);
106         }
107     }
108 
109     /**
110      * Externalizes this type element's content.
111      *
112      * @return the type element's content.
113      * @throws UnsupportedOperationException if the type element is not externalizable
114      */
115     ExternalizedTypeElement externalize();
116 
117     @Override
118     String toString();
119 
120     @Override
121     boolean equals(Object o);
122 
123     @Override
124     int hashCode();
125 }