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 jdk.incubator.code.parser.impl; 27 28 import jdk.incubator.code.parser.impl.Tokens.Token; 29 import jdk.incubator.code.parser.impl.Tokens.TokenKind; 30 import jdk.incubator.code.type.*; 31 import jdk.incubator.code.TypeElement; 32 import jdk.incubator.code.type.RecordTypeRef; 33 import jdk.incubator.code.type.impl.FieldRefImpl; 34 import jdk.incubator.code.type.impl.MethodRefImpl; 35 import jdk.incubator.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 // type element identifier 101 Tokens.Token t = l.accept(TokenKind.IDENTIFIER, 102 TokenKind.PLUS, TokenKind.SUB, TokenKind.DOT); 103 identifier.append(t.kind == TokenKind.IDENTIFIER ? t.name() : t.kind.name); 104 if (t.kind == TokenKind.IDENTIFIER) { 105 // keep going if we see "." 106 while (l.acceptIf(Tokens.TokenKind.DOT)) { 107 identifier.append(Tokens.TokenKind.DOT.name); 108 t = l.accept(Tokens.TokenKind.IDENTIFIER); 109 identifier.append(t.name()); 110 } 111 } 112 } 113 114 // Type parameters 115 List<TypeElement.ExternalizedTypeElement> args; 116 if (l.token().kind == Tokens.TokenKind.LT) { 117 args = new ArrayList<>(); 118 do { 119 l.nextToken(); 120 TypeElement.ExternalizedTypeElement arg = parseExTypeElem(l); 121 args.add(arg); 122 } while (l.token().kind == Tokens.TokenKind.COMMA); 123 l.accept(Tokens.TokenKind.GT); 124 } else { 125 args = List.of(); 126 } 127 128 // Parse array-like syntax []+ 129 int dims = 0; 130 while (l.acceptIf(Tokens.TokenKind.LBRACKET)) { 131 l.accept(Tokens.TokenKind.RBRACKET); 132 dims++; 133 } 134 135 TypeElement.ExternalizedTypeElement td = new TypeElement.ExternalizedTypeElement(identifier.toString(), args); 136 if (dims > 0) { 137 // If array-like then type definition becomes a child with identifier [+ 138 return new TypeElement.ExternalizedTypeElement("[".repeat(dims), List.of(td)); 139 } else { 140 return td; 141 } 142 } 143 144 static TypeElement parseTypeElement(Lexer l) { 145 TypeElement.ExternalizedTypeElement typeDesc = parseExTypeElem(l); 146 return CoreTypeFactory.CORE_TYPE_FACTORY.constructType(typeDesc); 147 } 148 149 // (T, T, T, T)R 150 static FunctionType parseMethodType(Lexer l) { 151 List<TypeElement> ptypes = new ArrayList<>(); 152 l.accept(Tokens.TokenKind.LPAREN); 153 if (l.token().kind != Tokens.TokenKind.RPAREN) { 154 ptypes.add(parseTypeElement(l)); 155 while (l.acceptIf(Tokens.TokenKind.COMMA)) { 156 ptypes.add(parseTypeElement(l)); 157 } 158 } 159 l.accept(Tokens.TokenKind.RPAREN); 160 TypeElement rtype = parseTypeElement(l); 161 return FunctionType.functionType(rtype, ptypes); 162 } 163 164 static MethodRef parseMethodRef(Lexer l) { 165 TypeElement refType = parseTypeElement(l); 166 167 l.accept(Tokens.TokenKind.COLCOL); 168 169 String methodName; 170 if (l.acceptIf(Tokens.TokenKind.LT)) { 171 // Special name such as "<new>" 172 Tokens.Token t = l.accept(Tokens.TokenKind.IDENTIFIER); 173 l.accept(Tokens.TokenKind.GT); 174 methodName = "<" + t.name() + ">"; 175 } else { 176 methodName = l.accept(Tokens.TokenKind.IDENTIFIER).name(); 177 } 178 179 FunctionType mtype = parseMethodType(l); 180 181 return new MethodRefImpl(refType, methodName, mtype); 182 } 183 184 static FieldRef parseFieldRef(Lexer l) { 185 TypeElement refType = parseTypeElement(l); 186 187 l.accept(Tokens.TokenKind.COLCOL); 188 189 String fieldName = l.accept(Tokens.TokenKind.IDENTIFIER).name(); 190 191 FunctionType mtype = parseMethodType(l); 192 if (!mtype.parameterTypes().isEmpty()) { 193 throw new IllegalArgumentException(); 194 } 195 return new FieldRefImpl(refType, fieldName, mtype.returnType()); 196 } 197 198 static RecordTypeRef parseRecordTypeRef(Lexer l) { 199 List<RecordTypeRef.ComponentRef> components = new ArrayList<>(); 200 l.accept(Tokens.TokenKind.LPAREN); 201 if (l.token().kind != Tokens.TokenKind.RPAREN) { 202 do { 203 TypeElement componentType = parseTypeElement(l); 204 String componentName = l.accept(Tokens.TokenKind.IDENTIFIER).name(); 205 206 components.add(new RecordTypeRef.ComponentRef(componentType, componentName)); 207 } while(l.acceptIf(Tokens.TokenKind.COMMA)); 208 } 209 l.accept(Tokens.TokenKind.RPAREN); 210 TypeElement recordType = parseTypeElement(l); 211 return new RecordTypeRefImpl(recordType, components); 212 } 213 }