1 /* 2 * Copyright 2012, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.smalidea; 33 34 import com.intellij.lang.PsiBuilder; 35 import com.intellij.lang.PsiBuilder.Marker; 36 import com.intellij.psi.TokenType; 37 import com.intellij.psi.tree.IElementType; 38 import org.antlr.runtime.CommonToken; 39 import org.antlr.runtime.Token; 40 import org.antlr.runtime.TokenSource; 41 import org.antlr.runtime.TokenStream; 42 import org.jetbrains.annotations.Nullable; 43 import org.jf.smali.InvalidToken; 44 import org.jf.smali.smaliParser; 45 46 import javax.annotation.Nonnull; 47 import java.util.ArrayList; 48 49 public class PsiBuilderTokenStream implements TokenStream { 50 @Nonnull private PsiBuilder psiBuilder; 51 @Nullable private CommonToken currentToken = null; 52 @Nonnull private ArrayList<Marker> markers = new ArrayList<PsiBuilder.Marker>(); 53 54 public PsiBuilderTokenStream(@Nonnull PsiBuilder psiBuilder) { 55 this.psiBuilder = psiBuilder; 56 } 57 58 @Override public Token LT(int k) { 59 if (k == 1) { 60 if (currentToken == null) { 61 buildCurrentToken(); 62 } 63 return currentToken; 64 } 65 throw new UnsupportedOperationException(); 66 } 67 68 @Override public int range() { 69 return currentToken==null?0:1; 70 } 71 72 @Override public Token get(int i) { 73 throw new UnsupportedOperationException(); 74 } 75 76 @Override public TokenSource getTokenSource() { 77 throw new UnsupportedOperationException(); 78 } 79 80 @Override public String toString(int start, int stop) { 81 throw new UnsupportedOperationException(); 82 } 83 84 @Override public String toString(Token start, Token stop) { 85 throw new UnsupportedOperationException(); 86 } 87 88 @Override public void consume() { 89 psiBuilder.advanceLexer(); 90 buildCurrentToken(); 91 } 92 93 private void buildCurrentToken() { 94 IElementType element = psiBuilder.getTokenType(); 95 if (element != null) { 96 if (element instanceof SmaliLexicalElementType) { 97 SmaliLexicalElementType elementType = (SmaliLexicalElementType)element; 98 currentToken = new CommonToken(elementType.tokenId, psiBuilder.getTokenText()); 99 } else if (element == TokenType.BAD_CHARACTER) { 100 currentToken = new InvalidToken("", psiBuilder.getTokenText()); 101 } else { 102 throw new UnsupportedOperationException(); 103 } 104 } else { 105 currentToken = new CommonToken(Token.EOF); 106 } 107 } 108 109 @Override public int LA(int i) { 110 IElementType elementType = psiBuilder.lookAhead(i-1); 111 if (elementType == null) { 112 return -1; 113 } else if (elementType instanceof SmaliLexicalElementType) { 114 return ((SmaliLexicalElementType)elementType).tokenId; 115 } else if (elementType == TokenType.BAD_CHARACTER) { 116 return smaliParser.INVALID_TOKEN; 117 } 118 throw new UnsupportedOperationException(); 119 } 120 121 @Override public int mark() { 122 int ret = markers.size(); 123 markers.add(psiBuilder.mark()); 124 return ret; 125 } 126 127 @Override public int index() { 128 return psiBuilder.getCurrentOffset(); 129 } 130 131 @Override public void rewind(int markerIndex) { 132 PsiBuilder.Marker marker = markers.get(markerIndex); 133 marker.rollbackTo(); 134 while (markerIndex < markers.size()) { 135 markers.remove(markerIndex); 136 } 137 } 138 139 @Override public void rewind() { 140 rewind(markers.size()-1); 141 mark(); 142 } 143 144 @Override public void release(int markerIndex) { 145 while (markerIndex < markers.size()) { 146 markers.remove(markerIndex).drop(); 147 } 148 } 149 150 @Override public void seek(int index) { 151 if (index < psiBuilder.getCurrentOffset()) { 152 throw new UnsupportedOperationException(); 153 } 154 while (index > psiBuilder.getCurrentOffset()) { 155 consume(); 156 } 157 } 158 159 @Override public int size() { 160 throw new UnsupportedOperationException(); 161 } 162 163 @Override public String getSourceName() { 164 return null; 165 } 166 } 167