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}