1 package java.lang.reflect.code.type;
  2 
  3 import java.lang.constant.ClassDesc;
  4 import java.lang.reflect.code.TypeElement;
  5 import java.lang.reflect.code.type.WildcardType.BoundKind;
  6 import java.util.ArrayList;
  7 import java.util.List;
  8 
  9 public final class CoreTypeFactory {
 10 
 11     private CoreTypeFactory() {
 12     }
 13 
 14     // Code model type factory composed
 15 
 16     /**
 17      * Create a code model factory combining and composing the construction
 18      * of code model types with types constructed from the given type factory.
 19      *
 20      * @param f the type factory.
 21      * @return the code model factory.
 22      */
 23     public static TypeElementFactory codeModelTypeFactory(TypeElementFactory f) {
 24         class CodeModelFactory implements TypeElementFactory {
 25             final TypeElementFactory thisThenF = this.andThen(f);
 26 
 27             @Override
 28             public TypeElement constructType(TypeElement.ExternalizedTypeElement tree) {
 29                 return switch (tree.identifier()) {
 30                     case VarType.NAME -> {
 31                         if (tree.arguments().size() != 1) {
 32                             throw new IllegalArgumentException();
 33                         }
 34 
 35                         TypeElement v = thisThenF.constructType(tree.arguments().getFirst());
 36                         if (v == null) {
 37                             throw new IllegalArgumentException("Bad type: " + tree);
 38                         }
 39                         yield VarType.varType(v);
 40                     }
 41                     case TupleType.NAME -> {
 42                         if (tree.arguments().isEmpty()) {
 43                             throw new IllegalArgumentException("Bad type: " + tree);
 44                         }
 45 
 46                         List<TypeElement> cs = new ArrayList<>(tree.arguments().size());
 47                         for (TypeElement.ExternalizedTypeElement child : tree.arguments()) {
 48                             TypeElement c = thisThenF.constructType(child);
 49                             if (c == null) {
 50                                 throw new IllegalArgumentException("Bad type: " + tree);
 51                             }
 52                             cs.add(c);
 53                         }
 54                         yield TupleType.tupleType(cs);
 55                     }
 56                     case FunctionType.NAME -> {
 57                         if (tree.arguments().isEmpty()) {
 58                             throw new IllegalArgumentException("Bad type: " + tree);
 59                         }
 60 
 61                         TypeElement rt = thisThenF.constructType(tree.arguments().getFirst());
 62                         if (rt == null) {
 63                             throw new IllegalArgumentException("Bad type: " + tree);
 64                         }
 65                         List<TypeElement> pts = new ArrayList<>(tree.arguments().size() - 1);
 66                         for (TypeElement.ExternalizedTypeElement child : tree.arguments().subList(1, tree.arguments().size())) {
 67                             TypeElement c = thisThenF.constructType(child);
 68                             if (c == null) {
 69                                 throw new IllegalArgumentException("Bad type: " + tree);
 70                             }
 71                             pts.add(c);
 72                         }
 73                         yield FunctionType.functionType(rt, pts);
 74                     }
 75                     default -> null;
 76                 };
 77             }
 78         }
 79         if (f instanceof CodeModelFactory) {
 80             throw new IllegalArgumentException();
 81         }
 82 
 83         return new CodeModelFactory().thisThenF;
 84     }
 85 
 86     // Java type factory
 87 
 88     /**
 89      * The Java type factory.
 90      */
 91     public static final TypeElementFactory JAVA_TYPE_FACTORY = new TypeElementFactory() {
 92         @Override
 93         public TypeElement constructType(TypeElement.ExternalizedTypeElement tree) {
 94             String identifier = tree.identifier();
 95             int dimensions = 0;
 96             if (identifier.startsWith("[")) {
 97                 if (tree.arguments().size() != 1) {
 98                     throw new IllegalArgumentException("Bad type: " + tree);
 99                 }
100                 for (int i = 1; i < identifier.length(); i++) {
101                     if (identifier.charAt(i) != '[') {
102                         throw new IllegalArgumentException("Bad type: " + tree);
103                     }
104                 }
105                 dimensions = identifier.length();
106                 tree = tree.arguments().getFirst();
107                 identifier = tree.identifier();
108             }
109 
110             List<JavaType> typeArguments = new ArrayList<>(tree.arguments().size());
111             for (TypeElement.ExternalizedTypeElement child : tree.arguments()) {
112                 TypeElement t = JAVA_TYPE_FACTORY.constructType(child);
113                 if (!(t instanceof JavaType a)) {
114                     throw new IllegalArgumentException("Bad type: " + tree);
115                 }
116                 typeArguments.add(a);
117             }
118             if (identifier.equals("+") || identifier.equals("-")) {
119                 // wildcard type
120                 BoundKind kind = identifier.equals("+") ?
121                         BoundKind.EXTENDS : BoundKind.SUPER;
122                 return JavaType.wildcard(kind, typeArguments.get(0));
123             } else if (identifier.startsWith("#")) {
124                 // type-var
125                 if (typeArguments.size() != 1) {
126                     throw new IllegalArgumentException("Bad type-variable bounds: " + tree);
127                 }
128                 String[] parts = identifier.substring(1).split("::");
129                 if (parts.length == 2) {
130                     // class type-var
131                     return JavaType.typeVarRef(parts[1],
132                             (ClassType)constructType(parseExTypeElem(parts[0])),
133                             typeArguments.get(0));
134                 } else {
135                     // method type-var
136                     return JavaType.typeVarRef(parts[2],
137                             parseMethodRef(String.format("%s::%s", parts[0], parts[1])),
138                             typeArguments.get(0));
139                 }
140             }
141             JavaType t = switch (identifier) {
142                 case "boolean" -> JavaType.BOOLEAN;
143                 case "byte" -> JavaType.BYTE;
144                 case "char" -> JavaType.CHAR;
145                 case "short" -> JavaType.SHORT;
146                 case "int" -> JavaType.INT;
147                 case "long" -> JavaType.LONG;
148                 case "float" -> JavaType.FLOAT;
149                 case "double" -> JavaType.DOUBLE;
150                 case "void" -> JavaType.VOID;
151                 default -> JavaType.type(ClassDesc.of(identifier));
152             };
153             if (!typeArguments.isEmpty()) {
154                 t = JavaType.parameterized(t, typeArguments);
155             }
156             return dimensions == 0 ?
157                     t : JavaType.array(t, dimensions);
158         }
159     };
160 
161 
162     /**
163      * The core type factory that can construct instance of {@link JavaType}
164      * or code model types such as {@link VarType} or {@link TupleType} that
165      * may contain instances of those types.
166      */
167     public static final TypeElementFactory CORE_TYPE_FACTORY = codeModelTypeFactory(JAVA_TYPE_FACTORY);
168 
169     // Copied code in jdk.compiler module throws UOE
170     static MethodRef parseMethodRef(String desc) {
171 /*__throw new UnsupportedOperationException();__*/        return java.lang.reflect.code.parser.impl.DescParser.parseMethodRef(desc);
172     }
173 
174     // Copied code in jdk.compiler module throws UOE
175     static TypeElement.ExternalizedTypeElement parseExTypeElem(String desc) {
176 /*__throw new UnsupportedOperationException();__*/        return java.lang.reflect.code.parser.impl.DescParser.parseExTypeElem(desc);
177     }
178 }