001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * 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
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.rt.signature;
018
019 import jet.typeinfo.TypeInfoVariance;
020
021 /**
022 * @see SignatureReader
023 */
024 public class JetSignatureReader {
025
026 private final String signature;
027
028 public JetSignatureReader(String signature) {
029 this.signature = signature;
030 }
031
032
033 public void accept(JetSignatureVisitor v) {
034 String signature = this.signature;
035 int len = signature.length();
036 int pos = acceptFormalTypeParameters(v);
037
038 if (signature.charAt(pos) == '(') {
039 pos++;
040 while (signature.charAt(pos) != ')') {
041 pos = parseType(signature, pos, v.visitParameterType());
042 }
043 pos = parseType(signature, pos + 1, v.visitReturnType());
044 while (pos < len) {
045 pos = parseType(signature, pos + 1, v.visitExceptionType());
046 }
047 }
048 else {
049 pos = parseType(signature, pos, v.visitSuperclass());
050 while (pos < len) {
051 pos = parseType(signature, pos, v.visitInterface());
052 }
053 }
054
055 if (pos != signature.length()) {
056 throw new IllegalStateException();
057 }
058 }
059
060 public int acceptFormalTypeParameters(JetSignatureVisitor v) {
061 int pos;
062 char c;
063 if (signature.length() > 0 && signature.charAt(0) == '<') {
064 pos = 1;
065 do {
066 TypeInfoVariance variance;
067 boolean reified = true;
068
069 if (signature.substring(pos).startsWith("erased ")) {
070 reified = false;
071 pos += "erased ".length();
072 }
073 if (signature.substring(pos).startsWith("in ")) {
074 variance = TypeInfoVariance.IN;
075 pos += "in ".length();
076 }
077 else if (signature.substring(pos).startsWith("out ")) {
078 variance = TypeInfoVariance.OUT;
079 pos += "out ".length();
080 }
081 else {
082 variance = TypeInfoVariance.INVARIANT;
083 pos += "".length();
084 }
085 int end = signature.indexOf(':', pos);
086 if (end < 0) {
087 throw new IllegalStateException();
088 }
089 String typeParameterName = signature.substring(pos, end);
090 if (typeParameterName.isEmpty()) {
091 throw new IllegalStateException("incorrect signature: " + signature);
092 }
093 JetSignatureVisitor parameterVisitor = v.visitFormalTypeParameter(typeParameterName, variance, reified);
094 pos = end + 1;
095
096 c = signature.charAt(pos);
097 if (c == 'L' || c == 'M' || c == '[' || c == 'T' || c == '?') {
098 pos = parseType(signature, pos, parameterVisitor.visitClassBound());
099 }
100
101 while ((c = signature.charAt(pos)) == ':') {
102 ++pos;
103 pos = parseType(signature, pos, parameterVisitor.visitInterfaceBound());
104 }
105
106 parameterVisitor.visitFormalTypeParameterEnd();
107 } while (c != '>');
108 ++pos;
109 }
110 else {
111 pos = 0;
112 }
113 return pos;
114 }
115
116 public void acceptFormalTypeParametersOnly(JetSignatureVisitor v) {
117 int r = acceptFormalTypeParameters(v);
118 if (r != signature.length()) {
119 throw new IllegalStateException();
120 }
121 }
122
123 public int acceptType(JetSignatureVisitor v) {
124 return parseType(this.signature, 0, v);
125 }
126
127 public void acceptTypeOnly(JetSignatureVisitor v) {
128 int r = acceptType(v);
129 if (r != signature.length()) {
130 throw new IllegalStateException();
131 }
132 }
133
134
135 private static int parseType(
136 String signature,
137 int pos,
138 JetSignatureVisitor v)
139 {
140 if (signature.length() == 0) {
141 throw new IllegalStateException();
142 }
143
144 char c;
145 int start;
146 int end;
147 boolean visited;
148 boolean inner;
149
150 boolean nullable;
151 if (signature.charAt(pos) == '?') {
152 nullable = true;
153 pos++;
154 }
155 else {
156 nullable = false;
157 }
158
159 switch (c = signature.charAt(pos++)) {
160 case 'Z':
161 case 'C':
162 case 'B':
163 case 'S':
164 case 'I':
165 case 'F':
166 case 'J':
167 case 'D':
168 case 'V':
169 v.visitBaseType(c, nullable);
170 return pos;
171
172 case '[':
173 switch (c = signature.charAt(pos)) {
174 case '+':
175 case '-':
176 return parseType(signature, pos + 1, v.visitArrayType(nullable, JetSignatureVariance.parseVariance(c)));
177 default:
178 return parseType(signature, pos, v.visitArrayType(nullable, JetSignatureVariance.INVARIANT));
179 }
180
181 case 'T':
182 end = signature.indexOf(';', pos);
183 v.visitTypeVariable(signature.substring(pos, end), nullable);
184 return end + 1;
185
186 case 'L':
187 case 'M':
188 boolean forceReal = signature.charAt(pos - 1) == 'M';
189 start = pos;
190 visited = false;
191 inner = false;
192 while (true) {
193 switch (c = signature.charAt(pos++)) {
194 case '.':
195 case ';':
196 if (!visited) {
197 parseTypeConstructor(signature, v, start, pos, inner, nullable, forceReal);
198 }
199 if (c == ';') {
200 v.visitEnd();
201 return pos;
202 }
203 visited = false;
204 inner = true;
205 break;
206
207 case '<':
208 parseTypeConstructor(signature, v, start, pos, inner, nullable, forceReal);
209 visited = true;
210 pos = parseTypeArguments(signature, pos, v);
211
212 default:
213 break;
214 }
215 }
216 default:
217 throw new IllegalStateException();
218 }
219 }
220
221 private static void parseTypeConstructor(
222 String signature,
223 JetSignatureVisitor v,
224 int start,
225 int pos,
226 boolean inner,
227 boolean nullable,
228 boolean forceReal
229 ) {
230 String name = signature.substring(start, pos - 1);
231 if (inner) {
232 v.visitInnerClassType(name, nullable, forceReal);
233 }
234 else {
235 v.visitClassType(name, nullable, forceReal);
236 }
237 }
238
239 private static int parseTypeArguments(String signature, int pos, JetSignatureVisitor v) {
240 char c;
241 while (true) {
242 switch (c = signature.charAt(pos)) {
243 case '>':
244 return pos;
245 case '*':
246 ++pos;
247 v.visitTypeArgument();
248 break;
249 case '+':
250 case '-':
251 pos = parseType(signature,
252 pos + 1,
253 v.visitTypeArgument(JetSignatureVariance.parseVariance(c)));
254 break;
255 default:
256 pos = parseType(signature,
257 pos,
258 v.visitTypeArgument(JetSignatureVariance.INVARIANT));
259 break;
260 }
261 }
262 }
263 }