/* * 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.tvl.goworks.editor.go.highlighter; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.atn.ATN; import org.antlr.v4.runtime.atn.ATNState; import org.antlr.v4.runtime.atn.LexerATNSimulator; import org.antlr.v4.runtime.atn.SetTransition; import org.antlr.v4.runtime.atn.Transition; import org.antlr.v4.runtime.misc.IntervalSet; import org.tvl.goworks.editor.go.highlighter.generated.AbstractGoHighlighterLexer; /** * * @author Sam Harwell */ public class GoHighlighterLexer extends AbstractGoHighlighterLexer { private static final char unicodeDigitPlaceholder = '\u0660'; private static final char unicodeLetterPlaceholder = '\u0101'; static { IntervalSet digitChars = new IntervalSet(); IntervalSet letterChars = new IntervalSet(); for (char c = 0; c < Character.MAX_VALUE; c++) { if (Character.isDigit(c)) { digitChars.add(c); } else if (Character.isLetter(c)) { letterChars.add(c); } } for (ATNState state : _ATN.states) { if (state == null || state.onlyHasEpsilonTransitions()) { continue; } for (int i = 0; i < state.getNumberOfTransitions(); i++) { Transition updated = patchTransition(state.transition(i), digitChars, letterChars); if (updated != null) { state.setTransition(i, updated); } } if (!state.isOptimized()) { continue; } for (int i = 0; i < state.getNumberOfOptimizedTransitions(); i++) { Transition updated = patchTransition(state.getOptimizedTransition(i), digitChars, letterChars); if (updated != null) { state.setOptimizedTransition(i, updated); } } } } private static Transition patchTransition(Transition transition, IntervalSet digitChars, IntervalSet letterChars) { switch (transition.getSerializationType()) { case Transition.ATOM: case Transition.RANGE: case Transition.SET: break; default: return null; } IntervalSet label = transition.label(); if (label == null) { return null; } IntervalSet updated = null; if (label.contains(unicodeDigitPlaceholder)) { updated = new IntervalSet(label); updated.addAll(digitChars); if (updated.size() == digitChars.size()) { updated = digitChars; } } if (label.contains(unicodeLetterPlaceholder)) { if (updated != null) { updated.addAll(label); } else { updated = new IntervalSet(label); } updated.addAll(letterChars); if (updated.size() == letterChars.size()) { updated = letterChars; } } if (updated == null) { return null; } return new SetTransition(transition.target, updated); } public GoHighlighterLexer(CharStream input) { super(input); _interp = new GoHighlighterATNSimulator(this, _ATN); } @Override public Token emit() { switch (_type) { // case TOKENS: // handleAcceptPositionForKeyword("tokens"); // setInTokens(true); // break; // // case OPTIONS: // handleAcceptPositionForKeyword("options"); // setInOptions(true); // break; // // case LABEL: // handleAcceptPositionForIdentifier(); // if (isInOptions()) { // _type = ValidGrammarOption; // } else if (isInTokens()) { // _type = IDENTIFIER; // } // // break; // // case RCURLY: // setInTokens(false); // setInOptions(false); // break; default: break; } return super.emit(); } private boolean handleAcceptPositionForIdentifier() { String tokenText = getText(); int identifierLength = 0; while (identifierLength < tokenText.length() && isIdentifierChar(tokenText.charAt(identifierLength))) { identifierLength++; } if (getInputStream().index() > _tokenStartCharIndex + identifierLength) { int offset = identifierLength - 1; getInterpreter().resetAcceptPosition(getInputStream(), _tokenStartCharIndex + offset, _tokenStartLine, _tokenStartCharPositionInLine + offset); return true; } return false; } private boolean handleAcceptPositionForKeyword(String keyword) { if (getInputStream().index() > _tokenStartCharIndex + keyword.length()) { int offset = keyword.length() - 1; getInterpreter().resetAcceptPosition(getInputStream(), _tokenStartCharIndex + offset, _tokenStartLine, _tokenStartCharPositionInLine + offset); return true; } return false; } @Override public GoHighlighterATNSimulator getInterpreter() { return (GoHighlighterATNSimulator)super.getInterpreter(); } private static boolean isIdentifierChar(char c) { return Character.isLetterOrDigit(c) || c == '_'; } protected static class GoHighlighterATNSimulator extends LexerATNSimulator { public GoHighlighterATNSimulator(Lexer recog, ATN atn) { super(recog, atn); } protected void resetAcceptPosition(CharStream input, int index, int line, int charPositionInLine) { input.seek(index); this.line = line; this.charPositionInLine = charPositionInLine; consume(input); } } }