/*
* Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC
* All rights reserved.
*
* The source code of this document is proprietary work, and is not licensed for
* distribution. For information about licensing, contact Sam Harwell at:
* sam@tunnelvisionlabs.com
*/
package org.antlr.works.editor.antlr4.classification;
import java.util.Iterator;
import org.antlr.netbeans.editor.classification.TokenTag;
import org.antlr.netbeans.editor.tagging.TaggedPositionRegion;
import org.antlr.netbeans.editor.tagging.Tagger;
import org.antlr.netbeans.editor.text.DocumentSnapshot;
import org.antlr.netbeans.editor.text.DocumentSnapshotLine;
import org.antlr.netbeans.editor.text.NormalizedSnapshotPositionRegionCollection;
import org.antlr.netbeans.editor.text.SnapshotPositionRegion;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenFactory;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenFactory;
import org.antlr.v4.runtime.TokenSource;
import org.antlr.v4.runtime.misc.Tuple;
import org.antlr.v4.runtime.misc.Tuple2;
import org.netbeans.api.annotations.common.NonNull;
import org.openide.filesystems.FileObject;
import org.openide.util.Parameters;
/**
*
* @author Sam Harwell
*/
public class TaggerTokenSource implements TokenSource {
private final DocumentSnapshot snapshot;
private final Tagger<TokenTag<Token>> tagger;
private final SnapshotPositionRegion region;
private final Iterable<TaggedPositionRegion<TokenTag<Token>>> tags;
private final Iterator<TaggedPositionRegion<TokenTag<Token>>> tagIterator;
private TokenTag<Token> previousTag;
private CharStream input;
private Tuple2<? extends TokenSource, CharStream> tokenFactorySourcePair;
private int line = -1;
private int charPositionInLine = -1;
private TokenFactory tokenFactory = CommonTokenFactory.DEFAULT;
public TaggerTokenSource(@NonNull Tagger<TokenTag<Token>> tagger, DocumentSnapshot snapshot) {
this(tagger, new SnapshotPositionRegion(snapshot, 0, snapshot.length()));
}
public TaggerTokenSource(@NonNull Tagger<TokenTag<Token>> tagger, @NonNull SnapshotPositionRegion region) {
this.snapshot = region.getSnapshot();
this.tagger = tagger;
this.region = region;
this.tags = this.tagger.getTags(new NormalizedSnapshotPositionRegionCollection(region));
this.tagIterator = this.tags.iterator();
}
@Override
public Token nextToken() {
if (previousTag != null && previousTag.getToken().getType() == Token.EOF) {
return previousTag.getToken();
}
if (tagIterator.hasNext()) {
previousTag = tagIterator.next().getTag();
} else {
TokenSource source = this;
String text = null;
int channel = Token.DEFAULT_CHANNEL;
int start = snapshot.length();
int stop = start - 1;
int lineCount = snapshot.getLineCount();
int lineLength = snapshot.findLineFromLineNumber(lineCount - 1).getLength();
previousTag = new TokenTag<>(tokenFactory.create(getTokenFactorySourcePair(), Token.EOF, text, channel, start, stop, lineCount, lineLength));
}
line = -1;
charPositionInLine = -1;
return previousTag.getToken();
}
@Override
public int getLine() {
updateLineInformation();
return line;
}
@Override
public int getCharPositionInLine() {
updateLineInformation();
return charPositionInLine;
}
private void updateLineInformation() {
if (line == -1) {
if (previousTag == null) {
if (region.getStart().getOffset() == 0) {
line = 1;
charPositionInLine = 0;
} else {
DocumentSnapshotLine snapshotLine = snapshot.findLineFromOffset(region.getStart().getOffset() + 1);
line = snapshotLine.getLineNumber() + 1;
charPositionInLine = region.getStart().getOffset() - snapshotLine.getStart().getOffset();
}
} else if (previousTag.getToken().getType() == Token.EOF) {
DocumentSnapshotLine snapshotLine = snapshot.findLineFromLineNumber(snapshot.getLineCount() - 1);
line = snapshotLine.getLineNumber() + 1;
charPositionInLine = snapshotLine.getLength();
} else {
DocumentSnapshotLine snapshotLine = snapshot.findLineFromOffset(previousTag.getToken().getStopIndex() + 1);
line = snapshotLine.getLineNumber() + 1;
charPositionInLine = previousTag.getToken().getStopIndex() + 1 - snapshotLine.getStart().getOffset();
}
}
}
@Override
public CharStream getInputStream() {
if (input == null) {
input = new DocumentSnapshotCharStream(snapshot);
tokenFactorySourcePair = Tuple.create(this, input);
}
return input;
}
@NonNull
protected Tuple2<? extends TokenSource, CharStream> getTokenFactorySourcePair() {
if (tokenFactorySourcePair == null) {
tokenFactorySourcePair = Tuple.create(this, getInputStream());
}
return tokenFactorySourcePair;
}
@Override
public String getSourceName() {
FileObject fileObject = snapshot.getVersionedDocument().getFileObject();
if (fileObject == null) {
return "Unknown Source File";
}
return fileObject.toURL().getFile();
}
@Override
public TokenFactory getTokenFactory() {
return tokenFactory;
}
@Override
public void setTokenFactory(TokenFactory tokenFactory) {
Parameters.notNull("tokenFactory", tokenFactory);
this.tokenFactory = tokenFactory;
}
}