1 /* 2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.reflect.code.parser.impl; 27 28 import java.lang.reflect.code.parser.impl.Tokens.Token; 29 import java.lang.reflect.code.parser.impl.Tokens.TokenKind; 30 import java.lang.reflect.code.type.*; 31 import java.lang.reflect.code.TypeElement; 32 import java.lang.reflect.code.type.RecordTypeRef; 33 import java.lang.reflect.code.type.impl.FieldRefImpl; 34 import java.lang.reflect.code.type.impl.MethodRefImpl; 35 import java.lang.reflect.code.type.impl.RecordTypeRefImpl; 36 import java.util.ArrayList; 37 import java.util.List; 38 39 public final class DescParser { 40 private DescParser() {} 41 42 /** 43 * Parse an externalized type element from its serialized textual form. 44 * @param desc the serialized externalized type element 45 * @return the externalized type element 46 */ 47 public static TypeElement.ExternalizedTypeElement parseExTypeElem(String desc) { 48 Scanner s = Scanner.factory().newScanner(desc); 49 s.nextToken(); 50 return parseExTypeElem(s); 51 } 52 53 /** 54 * Parse a method reference from its serialized textual form. 55 * 56 * @param desc the serialized method reference 57 * @return the method reference 58 */ 59 public static MethodRef parseMethodRef(String desc) { 60 Scanner s = Scanner.factory().newScanner(desc); 61 s.nextToken(); 62 return parseMethodRef(s); 63 } 64 65 /** 66 * Parse a field reference from its serialized textual form. 67 * 68 * @param desc the serialized field reference 69 * @return the field reference 70 */ 71 public static FieldRef parseFieldRef(String desc) { 72 Scanner s = Scanner.factory().newScanner(desc); 73 s.nextToken(); 74 return parseFieldRef(s); 75 } 76 77 /** 78 * Parse a record type reference from its serialized textual form. 79 * 80 * @param desc the serialized record type reference 81 * @return the record type reference 82 */ 83 public static RecordTypeRef parseRecordTypeRef(String desc) { 84 Scanner s = Scanner.factory().newScanner(desc); 85 s.nextToken(); 86 return parseRecordTypeRef(s); 87 } 88 89 public static TypeElement.ExternalizedTypeElement parseExTypeElem(Lexer l) { 90 StringBuilder identifier = new StringBuilder(); 91 if (l.token().kind == TokenKind.HASH) { 92 // Quoted identifier 93 Token t = l.token(); 94 while (t.kind != TokenKind.LT) { 95 identifier.append(t.kind == TokenKind.IDENTIFIER ? t.name() : t.kind.name); 96 l.nextToken(); 97 t = l.token(); 98 } 99 } else { 100 // Qualified identifier 101 Tokens.Token t = l.accept(TokenKind.IDENTIFIER, 102 TokenKind.PLUS, TokenKind.SUB); 103 identifier.append(t.kind == TokenKind.IDENTIFIER ? t.name() : t.kind.name); 104 while (l.acceptIf(Tokens.TokenKind.DOT)) { 105 identifier.append(Tokens.TokenKind.DOT.name); 106 t = l.accept(Tokens.TokenKind.IDENTIFIER); 107 identifier.append(t.name()); 108 } 109 } 110 111 // Type parameters 112 List<TypeElement.ExternalizedTypeElement> args; 113 if (l.token().kind == Tokens.TokenKind.LT) { 114 args = new ArrayList<>(); 115 do { 116 l.nextToken(); 117 TypeElement.ExternalizedTypeElement arg = parseExTypeElem(l); 118 args.add(arg); 119 } while (l.token().kind == Tokens.TokenKind.COMMA); 120 l.accept(Tokens.TokenKind.GT); 121 } else { 122 args = List.of(); 123 } 124 125 // @@@ Enclosed/inner classes, separated by $ which may also be parameterized 126 127 // Parse array-like syntax []+ 128 int dims = 0; 129 while (l.acceptIf(Tokens.TokenKind.LBRACKET)) { 130 l.accept(Tokens.TokenKind.RBRACKET); 131 dims++; 132 } 133 134 TypeElement.ExternalizedTypeElement td = new TypeElement.ExternalizedTypeElement(identifier.toString(), args); 135 if (dims > 0) { 136 // If array-like then type definition becomes a child with identifier [+ 137 return new TypeElement.ExternalizedTypeElement("[".repeat(dims), List.of(td)); 138 } else { 139 return td; 140 } 141 } 142 143 static TypeElement parseTypeElement(Lexer l) { 144 TypeElement.ExternalizedTypeElement typeDesc = parseExTypeElem(l); 145 return CoreTypeFactory.CORE_TYPE_FACTORY.constructType(typeDesc); 146 } 147 148 // (T, T, T, T)R 149 static FunctionType parseMethodType(Lexer l) { 150 List<TypeElement> ptypes = new ArrayList<>(); 151 l.accept(Tokens.TokenKind.LPAREN); 152 if (l.token().kind != Tokens.TokenKind.RPAREN) { 153 ptypes.add(parseTypeElement(l)); 154 while (l.acceptIf(Tokens.TokenKind.COMMA)) { 155 ptypes.add(parseTypeElement(l)); 156 } 157 } 158 l.accept(Tokens.TokenKind.RPAREN); 159 TypeElement rtype = parseTypeElement(l); 160 return FunctionType.functionType(rtype, ptypes); 161 } 162 163 static MethodRef parseMethodRef(Lexer l) { 164 TypeElement refType = parseTypeElement(l); 165 166 l.accept(Tokens.TokenKind.COLCOL); 167 168 String methodName; 169 if (l.acceptIf(Tokens.TokenKind.LT)) { 170 // Special name such as "<new>" 171 Tokens.Token t = l.accept(Tokens.TokenKind.IDENTIFIER); 172 l.accept(Tokens.TokenKind.GT); 173 methodName = "<" + t.name() + ">"; 174 } else { 175 methodName = l.accept(Tokens.TokenKind.IDENTIFIER).name(); 176 } 177 178 FunctionType mtype = parseMethodType(l); 179 180 return new MethodRefImpl(refType, methodName, mtype); 181 } 182 183 static FieldRef parseFieldRef(Lexer l) { 184 TypeElement refType = parseTypeElement(l); 185 186 l.accept(Tokens.TokenKind.COLCOL); 187 188 String fieldName = l.accept(Tokens.TokenKind.IDENTIFIER).name(); 189 190 FunctionType mtype = parseMethodType(l); 191 if (!mtype.parameterTypes().isEmpty()) { 192 throw new IllegalArgumentException(); 193 } 194 return new FieldRefImpl(refType, fieldName, mtype.returnType()); 195 } 196 197 static RecordTypeRef parseRecordTypeRef(Lexer l) { 198 List<RecordTypeRef.ComponentRef> components = new ArrayList<>(); 199 l.accept(Tokens.TokenKind.LPAREN); 200 if (l.token().kind != Tokens.TokenKind.RPAREN) { 201 do { 202 TypeElement componentType = parseTypeElement(l); 203 String componentName = l.accept(Tokens.TokenKind.IDENTIFIER).name(); 204 205 components.add(new RecordTypeRef.ComponentRef(componentType, componentName)); 206 } while(l.acceptIf(Tokens.TokenKind.COMMA)); 207 } 208 l.accept(Tokens.TokenKind.RPAREN); 209 TypeElement recordType = parseTypeElement(l); 210 return new RecordTypeRefImpl(recordType, components); 211 } 212 }