/*
* Copyright 2009-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eclipse.jdt.groovy.core.util;
import java.io.Reader;
import java.io.StringReader;
import groovyjarjarantlr.Token;
import groovyjarjarantlr.TokenStream;
import groovyjarjarantlr.TokenStreamException;
import org.codehaus.groovy.antlr.parser.GroovyLexer;
import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
/**
* A wrapper around an Antlr Groovy Scanner, providing a convenient interface to tokenize a snippet of groovy code.
*
* @author kdvolder
*/
public class GroovyScanner {
private TokenStream stream;
private GroovyLexer lexer;
private boolean whiteSpaceIncluded;
public GroovyScanner(Reader input) {
this(input, false);
}
public GroovyScanner(Reader input, boolean whiteSpaceIncluded) {
init(input, whiteSpaceIncluded);
}
private void init(Reader input, boolean whiteSpaceIncluded) {
this.whiteSpaceIncluded = whiteSpaceIncluded;
lexer = new GroovyLexer(input);
lexer.setWhitespaceIncluded(whiteSpaceIncluded);
this.stream = lexer.plumb();
/*
* TODO Remove ones http://jira.codehaus.org/browse/GROOVY-6608 is fixed Initializes the parser to avoid NPE in Groovy code
*/
GroovyRecognizer.make(lexer);
}
public GroovyScanner(String text) {
this(new StringReader(text), false);
}
public Token nextToken() throws TokenStreamException {
return stream.nextToken();
}
/**
* Attempt to recover after a scanning error. We will recreate the Antlr lexer one character past the place where we got an
* error and try to continue scanning from there.
*
* @throws BadLocationException
*/
public void recover(IDocument document) throws BadLocationException {
int line = lexer.getInputState().getLine(); // Line and
int col = lexer.getInputState().getColumn(); // column where error happened.
int offset = getOffset(document, line, col) + 1; // +1 to skip one character.
line = document.getLineOfOffset(offset);
int lineStart = document.getLineOffset(line);
line = line + 1; // antlr lines start at 1
col = offset - lineStart + 1; // antlr cols start at 1
String remainingInput = document.get(offset, document.getLength() - offset);
init(new StringReader(remainingInput), whiteSpaceIncluded); // Reinitialize with remaining input
lexer.setLine(line); // Fix antlr line and
lexer.setColumn(col);// column infos because we are not starting at the start
}
/**
* Convert antlr line / col position into a IDocument offset.
*
* @param document The reference document
* @param line antlr style line number (starts at 1)
* @param col antlr style col number (starts at 1)
*/
public static int getOffset(IDocument document, int line, int col) throws BadLocationException {
return document.getLineOffset(line - 1) + col - 1;
}
}