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    }