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 017package org.jetbrains.jet.rt.signature; 018 019import jet.typeinfo.TypeInfoVariance; 020 021/** 022 * @see SignatureWriter 023 */ 024public 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}