001    /*
002     * Copyright 2010-2015 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.kotlin.parsing;
018    
019    import com.intellij.psi.tree.IElementType;
020    
021    public class TruncatedSemanticWhitespaceAwarePsiBuilder extends SemanticWhitespaceAwarePsiBuilderAdapter {
022    
023        private final int myEOFPosition;
024    
025        public TruncatedSemanticWhitespaceAwarePsiBuilder(SemanticWhitespaceAwarePsiBuilder builder, int eofPosition) {
026            super(builder);
027            this.myEOFPosition = eofPosition;
028        }
029    
030        @Override
031        public boolean eof() {
032            return super.eof() || isOffsetBeyondEof(getCurrentOffset());
033        }
034    
035        @Override
036        public String getTokenText() {
037            if (eof()) return null;
038            return super.getTokenText();
039        }
040    
041        @Override
042        public IElementType getTokenType() {
043            if (eof()) return null;
044            return super.getTokenType();
045        }
046    
047        @Override
048        public IElementType lookAhead(int steps) {
049            if (eof()) return null;
050    
051            int rawLookAheadSteps = rawLookAhead(steps);
052            if (isOffsetBeyondEof(rawTokenTypeStart(rawLookAheadSteps))) return null;
053    
054            return super.rawLookup(rawLookAheadSteps);
055        }
056    
057        private int rawLookAhead(int steps) {
058            // This code reproduces the behavior of PsiBuilderImpl.lookAhead(), but returns a number of raw steps instead of a token type
059            // This is required for implementing truncated builder behavior
060            int cur = 0;
061            while (steps > 0) {
062                cur++;
063    
064                IElementType rawTokenType = rawLookup(cur);
065                while (rawTokenType != null && isWhitespaceOrComment(rawTokenType)) {
066                    cur++;
067                    rawTokenType = rawLookup(cur);
068                }
069    
070                steps--;
071            }
072            return cur;
073        }
074    
075        private boolean isOffsetBeyondEof(int offsetFromCurrent) {
076            return myEOFPosition >= 0 && offsetFromCurrent >= myEOFPosition;
077        }
078    }