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 SignatureWriter
023 */
024 public class JetSignatureWriter implements JetSignatureVisitor {
025
026 /**
027 * Buffer used to construct the signature.
028 */
029 private final StringBuffer buf = new StringBuffer();
030
031 /**
032 * Indicates if the signature contains formal type parameters.
033 */
034 private boolean hasFormals;
035
036 /**
037 * Indicates if the signature contains method parameter types.
038 */
039 private boolean hasParameters;
040
041 /**
042 * Stack used to keep track of class types that have arguments. Each element
043 * of this stack is a boolean encoded in one bit. The top of the stack is
044 * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
045 * /2.
046 */
047 private int argumentStack;
048
049 /**
050 * Constructs a new {@link SignatureWriter} object.
051 */
052 public JetSignatureWriter() {
053 }
054
055 // ------------------------------------------------------------------------
056 // Implementation of the SignatureVisitor interface
057 // ------------------------------------------------------------------------
058
059 @Override
060 public JetSignatureVisitor visitFormalTypeParameter(String name, TypeInfoVariance variance, boolean reified) {
061 if (!hasFormals) {
062 hasFormals = true;
063 buf.append('<');
064 }
065 if (!reified) {
066 buf.append("erased ");
067 }
068 switch (variance) {
069 case OUT:
070 buf.append("out ");
071 break;
072 case IN:
073 buf.append("in ");
074 break;
075 case INVARIANT:
076 break;
077 default:
078 throw new IllegalStateException();
079 }
080 buf.append(name);
081 buf.append(':');
082 return this;
083 }
084
085 @Override
086 public void visitFormalTypeParameterEnd() {
087 }
088
089 @Override
090 public JetSignatureWriter visitClassBound() {
091 return this;
092 }
093
094 @Override
095 public JetSignatureWriter visitInterfaceBound() {
096 buf.append(':');
097 return this;
098 }
099
100 @Override
101 public JetSignatureWriter visitSuperclass() {
102 endFormals();
103 return this;
104 }
105
106 @Override
107 public JetSignatureWriter visitInterface() {
108 return this;
109 }
110
111 @Override
112 public JetSignatureWriter visitParameterType() {
113 endFormals();
114 if (!hasParameters) {
115 hasParameters = true;
116 buf.append('(');
117 }
118 return this;
119 }
120
121 @Override
122 public JetSignatureWriter visitReturnType() {
123 endFormals();
124 if (!hasParameters) {
125 buf.append('(');
126 }
127 buf.append(')');
128 return this;
129 }
130
131 @Override
132 public JetSignatureWriter visitExceptionType() {
133 buf.append('^');
134 return this;
135 }
136
137 private void visitNullabe(boolean nullable) {
138 if (nullable) {
139 buf.append('?');
140 }
141 }
142
143 @Override
144 public void visitBaseType(char descriptor, boolean nullable) {
145 visitNullabe(nullable);
146 buf.append(descriptor);
147 }
148
149 @Override
150 public void visitTypeVariable(String name, boolean nullable) {
151 visitNullabe(nullable);
152 buf.append('T');
153 buf.append(name);
154 buf.append(';');
155 }
156
157 @Override
158 public JetSignatureWriter visitArrayType(boolean nullable, JetSignatureVariance wildcard) {
159 visitNullabe(nullable);
160 buf.append('[');
161 if (wildcard != JetSignatureVariance.INVARIANT) {
162 buf.append(wildcard.getChar());
163 }
164 return this;
165 }
166
167 @Override
168 public void visitClassType(String name, boolean nullable, boolean forceReal) {
169 visitNullabe(nullable);
170 buf.append(forceReal ? 'M' : 'L');
171 buf.append(name);
172 argumentStack *= 2;
173 }
174
175 @Override
176 public void visitInnerClassType(String name, boolean nullable, boolean forceReal) {
177 endArguments();
178 visitNullabe(nullable);
179 buf.append('.');
180 buf.append(name);
181 argumentStack *= 2;
182 }
183
184 @Override
185 public void visitTypeArgument() {
186 if (argumentStack % 2 == 0) {
187 ++argumentStack;
188 buf.append('<');
189 }
190 buf.append('*');
191 }
192
193 @Override
194 public JetSignatureWriter visitTypeArgument(JetSignatureVariance variance) {
195 if (argumentStack % 2 == 0) {
196 ++argumentStack;
197 buf.append('<');
198 }
199 if (variance != JetSignatureVariance.INVARIANT) {
200 buf.append(variance.getChar());
201 }
202 return this;
203 }
204
205 @Override
206 public void visitEnd() {
207 endArguments();
208 buf.append(';');
209 }
210
211 public String toString() {
212 return buf.toString();
213 }
214
215 // ------------------------------------------------------------------------
216 // Utility methods
217 // ------------------------------------------------------------------------
218
219 /**
220 * Ends the formal type parameters section of the signature.
221 */
222 private void endFormals() {
223 if (hasFormals) {
224 hasFormals = false;
225 buf.append('>');
226 }
227 }
228
229 /**
230 * Ends the type arguments of a class or inner class type.
231 */
232 private void endArguments() {
233 if (argumentStack % 2 != 0) {
234 buf.append('>');
235 }
236 argumentStack /= 2;
237 }
238 }