Cloud.Liu
4 years ago
245 changed files with 293 additions and 34971 deletions
@ -1,6 +0,0 @@
|
||||
*.iml |
||||
.idea/ |
||||
.DS_Store |
||||
.project |
||||
.classpath |
||||
*.gradle |
@ -1,239 +0,0 @@
|
||||
# Doxyfile 1.5.2 |
||||
|
||||
#--------------------------------------------------------------------------- |
||||
# Project related configuration options |
||||
#--------------------------------------------------------------------------- |
||||
DOXYFILE_ENCODING = UTF-8 |
||||
PROJECT_NAME = "ANTLR v4 API" |
||||
PROJECT_NUMBER = 4.0 |
||||
OUTPUT_DIRECTORY = api/Java |
||||
CREATE_SUBDIRS = NO |
||||
OUTPUT_LANGUAGE = English |
||||
BRIEF_MEMBER_DESC = YES |
||||
REPEAT_BRIEF = YES |
||||
ABBREVIATE_BRIEF = "The $name class" \ |
||||
"The $name widget" \ |
||||
"The $name file" \ |
||||
is \ |
||||
provides \ |
||||
specifies \ |
||||
contains \ |
||||
represents \ |
||||
a \ |
||||
an \ |
||||
the |
||||
ALWAYS_DETAILED_SEC = YES |
||||
INLINE_INHERITED_MEMB = NO |
||||
FULL_PATH_NAMES = YES |
||||
STRIP_FROM_PATH = /Applications/ |
||||
STRIP_FROM_INC_PATH = |
||||
SHORT_NAMES = NO |
||||
JAVADOC_AUTOBRIEF = NO |
||||
MULTILINE_CPP_IS_BRIEF = NO |
||||
DETAILS_AT_TOP = NO |
||||
INHERIT_DOCS = YES |
||||
SEPARATE_MEMBER_PAGES = NO |
||||
TAB_SIZE = 4 |
||||
ALIASES = |
||||
OPTIMIZE_OUTPUT_FOR_C = NO |
||||
OPTIMIZE_OUTPUT_JAVA = YES |
||||
BUILTIN_STL_SUPPORT = NO |
||||
CPP_CLI_SUPPORT = NO |
||||
DISTRIBUTE_GROUP_DOC = NO |
||||
SUBGROUPING = YES |
||||
#--------------------------------------------------------------------------- |
||||
# Build related configuration options |
||||
#--------------------------------------------------------------------------- |
||||
EXTRACT_ALL = YES |
||||
EXTRACT_PRIVATE = YES |
||||
EXTRACT_STATIC = YES |
||||
EXTRACT_LOCAL_CLASSES = YES |
||||
EXTRACT_LOCAL_METHODS = NO |
||||
HIDE_UNDOC_MEMBERS = NO |
||||
HIDE_UNDOC_CLASSES = NO |
||||
HIDE_FRIEND_COMPOUNDS = NO |
||||
HIDE_IN_BODY_DOCS = NO |
||||
INTERNAL_DOCS = NO |
||||
CASE_SENSE_NAMES = NO |
||||
HIDE_SCOPE_NAMES = NO |
||||
SHOW_INCLUDE_FILES = YES |
||||
INLINE_INFO = YES |
||||
SORT_MEMBER_DOCS = YES |
||||
SORT_BRIEF_DOCS = NO |
||||
SORT_BY_SCOPE_NAME = NO |
||||
GENERATE_TODOLIST = YES |
||||
GENERATE_TESTLIST = NO |
||||
GENERATE_BUGLIST = NO |
||||
GENERATE_DEPRECATEDLIST= NO |
||||
ENABLED_SECTIONS = |
||||
MAX_INITIALIZER_LINES = 30 |
||||
SHOW_USED_FILES = YES |
||||
SHOW_DIRECTORIES = NO |
||||
FILE_VERSION_FILTER = |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options related to warning and progress messages |
||||
#--------------------------------------------------------------------------- |
||||
QUIET = NO |
||||
WARNINGS = YES |
||||
WARN_IF_UNDOCUMENTED = YES |
||||
WARN_IF_DOC_ERROR = YES |
||||
WARN_NO_PARAMDOC = NO |
||||
WARN_FORMAT = "$file:$line: $text" |
||||
WARN_LOGFILE = |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options related to the input files |
||||
#--------------------------------------------------------------------------- |
||||
INPUT = /Users/parrt/antlr/code/antlr4/runtime/Java/src |
||||
INPUT_ENCODING = UTF-8 |
||||
FILE_PATTERNS = *.java |
||||
RECURSIVE = YES |
||||
EXCLUDE = |
||||
EXCLUDE_SYMLINKS = NO |
||||
EXCLUDE_PATTERNS = |
||||
EXCLUDE_SYMBOLS = java::util \ |
||||
java::io |
||||
EXAMPLE_PATH = |
||||
EXAMPLE_PATTERNS = * |
||||
EXAMPLE_RECURSIVE = NO |
||||
IMAGE_PATH = |
||||
INPUT_FILTER = |
||||
FILTER_PATTERNS = |
||||
FILTER_SOURCE_FILES = NO |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options related to source browsing |
||||
#--------------------------------------------------------------------------- |
||||
SOURCE_BROWSER = YES |
||||
INLINE_SOURCES = NO |
||||
STRIP_CODE_COMMENTS = YES |
||||
REFERENCED_BY_RELATION = NO |
||||
REFERENCES_RELATION = NO |
||||
REFERENCES_LINK_SOURCE = YES |
||||
USE_HTAGS = NO |
||||
VERBATIM_HEADERS = YES |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options related to the alphabetical class index |
||||
#--------------------------------------------------------------------------- |
||||
ALPHABETICAL_INDEX = YES |
||||
COLS_IN_ALPHA_INDEX = 5 |
||||
IGNORE_PREFIX = |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options related to the HTML output |
||||
#--------------------------------------------------------------------------- |
||||
GENERATE_HTML = YES |
||||
HTML_OUTPUT = . |
||||
HTML_FILE_EXTENSION = .html |
||||
HTML_HEADER = |
||||
HTML_FOOTER = |
||||
HTML_STYLESHEET = |
||||
HTML_ALIGN_MEMBERS = YES |
||||
HTML_DYNAMIC_SECTIONS = YES |
||||
GENERATE_HTMLHELP = NO |
||||
CHM_FILE = |
||||
HHC_LOCATION = |
||||
GENERATE_CHI = NO |
||||
BINARY_TOC = NO |
||||
TOC_EXPAND = NO |
||||
DISABLE_INDEX = NO |
||||
ENUM_VALUES_PER_LINE = 4 |
||||
GENERATE_TREEVIEW = YES |
||||
TREEVIEW_WIDTH = 210 |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options related to the LaTeX output |
||||
#--------------------------------------------------------------------------- |
||||
GENERATE_LATEX = NO |
||||
LATEX_OUTPUT = latex |
||||
LATEX_CMD_NAME = latex |
||||
MAKEINDEX_CMD_NAME = makeindex |
||||
COMPACT_LATEX = NO |
||||
PAPER_TYPE = a4wide |
||||
EXTRA_PACKAGES = |
||||
LATEX_HEADER = |
||||
PDF_HYPERLINKS = NO |
||||
USE_PDFLATEX = YES |
||||
LATEX_BATCHMODE = NO |
||||
LATEX_HIDE_INDICES = NO |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options related to the RTF output |
||||
#--------------------------------------------------------------------------- |
||||
GENERATE_RTF = NO |
||||
RTF_OUTPUT = rtf |
||||
COMPACT_RTF = NO |
||||
RTF_HYPERLINKS = NO |
||||
RTF_STYLESHEET_FILE = |
||||
RTF_EXTENSIONS_FILE = |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options related to the man page output |
||||
#--------------------------------------------------------------------------- |
||||
GENERATE_MAN = NO |
||||
MAN_OUTPUT = man |
||||
MAN_EXTENSION = .3 |
||||
MAN_LINKS = NO |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options related to the XML output |
||||
#--------------------------------------------------------------------------- |
||||
GENERATE_XML = NO |
||||
XML_OUTPUT = xml |
||||
XML_SCHEMA = |
||||
XML_DTD = |
||||
XML_PROGRAMLISTING = YES |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options for the AutoGen Definitions output |
||||
#--------------------------------------------------------------------------- |
||||
GENERATE_AUTOGEN_DEF = NO |
||||
#--------------------------------------------------------------------------- |
||||
# configuration options related to the Perl module output |
||||
#--------------------------------------------------------------------------- |
||||
GENERATE_PERLMOD = NO |
||||
PERLMOD_LATEX = NO |
||||
PERLMOD_PRETTY = YES |
||||
PERLMOD_MAKEVAR_PREFIX = |
||||
#--------------------------------------------------------------------------- |
||||
# Configuration options related to the preprocessor |
||||
#--------------------------------------------------------------------------- |
||||
ENABLE_PREPROCESSING = YES |
||||
MACRO_EXPANSION = NO |
||||
EXPAND_ONLY_PREDEF = NO |
||||
SEARCH_INCLUDES = YES |
||||
INCLUDE_PATH = |
||||
INCLUDE_FILE_PATTERNS = |
||||
PREDEFINED = |
||||
EXPAND_AS_DEFINED = |
||||
SKIP_FUNCTION_MACROS = YES |
||||
#--------------------------------------------------------------------------- |
||||
# Configuration::additions related to external references |
||||
#--------------------------------------------------------------------------- |
||||
TAGFILES = |
||||
GENERATE_TAGFILE = |
||||
ALLEXTERNALS = NO |
||||
EXTERNAL_GROUPS = YES |
||||
PERL_PATH = /usr/bin/perl |
||||
#--------------------------------------------------------------------------- |
||||
# Configuration options related to the dot tool |
||||
#--------------------------------------------------------------------------- |
||||
CLASS_DIAGRAMS = NO |
||||
MSCGEN_PATH = /Applications/Doxygen.app/Contents/Resources/ |
||||
HIDE_UNDOC_RELATIONS = YES |
||||
HAVE_DOT = YES |
||||
CLASS_GRAPH = YES |
||||
COLLABORATION_GRAPH = NO |
||||
GROUP_GRAPHS = NO |
||||
UML_LOOK = NO |
||||
TEMPLATE_RELATIONS = NO |
||||
INCLUDE_GRAPH = YES |
||||
INCLUDED_BY_GRAPH = YES |
||||
CALL_GRAPH = NO |
||||
CALLER_GRAPH = NO |
||||
GRAPHICAL_HIERARCHY = YES |
||||
DIRECTORY_GRAPH = YES |
||||
DOT_IMAGE_FORMAT = png |
||||
DOT_PATH = /Applications/Doxygen.app/Contents/Resources/ |
||||
DOTFILE_DIRS = |
||||
DOT_GRAPH_MAX_NODES = 50 |
||||
DOT_TRANSPARENT = NO |
||||
DOT_MULTI_TARGETS = NO |
||||
GENERATE_LEGEND = YES |
||||
DOT_CLEANUP = YES |
||||
#--------------------------------------------------------------------------- |
||||
# Configuration::additions related to the search engine |
||||
#--------------------------------------------------------------------------- |
||||
SEARCHENGINE = YES |
Binary file not shown.
@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
~ Use of this file is governed by the BSD 3-clause license that |
||||
~ can be found in the LICENSE.txt file in the project root. |
||||
--> |
||||
|
||||
<project-shared-configuration> |
||||
<!-- |
||||
This file contains additional configuration written by modules in the NetBeans IDE. |
||||
The configuration is intended to be shared among all the users of project and |
||||
therefore it is assumed to be part of version control checkout. |
||||
Without this configuration present, some functionality in the IDE may be limited or fail altogether. |
||||
--> |
||||
<spellchecker-wordlist xmlns="http://www.netbeans.org/ns/spellchecker-wordlist/1"> |
||||
<word>rule's</word> |
||||
<word>validator</word> |
||||
</spellchecker-wordlist> |
||||
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> |
||||
<!-- |
||||
Properties that influence various parts of the IDE, especially code formatting and the like. |
||||
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. |
||||
That way multiple projects can share the same settings (useful for formatting rules for example). |
||||
Any value defined here will override the pom.xml file value but is only applicable to the current project. |
||||
--> |
||||
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile> |
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab>4</org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab> |
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.tab-size>4</org-netbeans-modules-editor-indent.CodeStyle.project.tab-size> |
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width> |
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>true</org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs> |
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width> |
||||
<org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap> |
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indentCasesFromSwitch>false</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indentCasesFromSwitch> |
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab> |
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size> |
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width> |
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs>false</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs> |
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-limit-width> |
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-line-wrap> |
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.continuationIndentSize>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.continuationIndentSize> |
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder>*;javax;java</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder> |
||||
<netbeans.compile.on.save>test</netbeans.compile.on.save> |
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceAfterTypeCast>false</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceAfterTypeCast> |
||||
</properties> |
||||
</project-shared-configuration> |
@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<parent> |
||||
<groupId>com.fr.third</groupId> |
||||
<artifactId>step1</artifactId> |
||||
<version>${revision}</version> |
||||
<relativePath>../base-third-project/base-third-step1</relativePath> |
||||
</parent> |
||||
|
||||
<artifactId>fine-antlr4</artifactId> |
||||
<version>${revision}</version> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>com.fr.third</groupId> |
||||
<artifactId>org.abego.treelayout.core</artifactId> |
||||
<version>local</version> |
||||
<scope>system</scope> |
||||
<systemPath>${basedir}/lib/org.abego.treelayout.core.jar</systemPath> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
</project> |
@ -1,181 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNConfigSet; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.DecisionInfo; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ParserATNSimulator; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.PredictionMode; |
||||
import com.fr.third.org.antlr.v4.runtime.dfa.DFA; |
||||
|
||||
import java.util.BitSet; |
||||
|
||||
/** How to emit recognition errors. */ |
||||
public interface ANTLRErrorListener { |
||||
/** |
||||
* Upon syntax error, notify any interested parties. This is not how to |
||||
* recover from errors or compute error messages. {@link ANTLRErrorStrategy} |
||||
* specifies how to recover from syntax errors and how to compute error |
||||
* messages. This listener's job is simply to emit a computed message, |
||||
* though it has enough information to create its own message in many cases. |
||||
* |
||||
* <p>The {@link RecognitionException} is non-null for all syntax errors except |
||||
* when we discover mismatched token errors that we can recover from |
||||
* in-line, without returning from the surrounding rule (via the single |
||||
* token insertion and deletion mechanism).</p> |
||||
* |
||||
* @param recognizer |
||||
* What parser got the error. From this |
||||
* object, you can access the context as well |
||||
* as the input stream. |
||||
* @param offendingSymbol |
||||
* The offending token in the input token |
||||
* stream, unless recognizer is a lexer (then it's null). If |
||||
* no viable alternative error, {@code e} has token at which we |
||||
* started production for the decision. |
||||
* @param line |
||||
* The line number in the input where the error occurred. |
||||
* @param charPositionInLine |
||||
* The character position within that line where the error occurred. |
||||
* @param msg |
||||
* The message to emit. |
||||
* @param e |
||||
* The exception generated by the parser that led to |
||||
* the reporting of an error. It is null in the case where |
||||
* the parser was able to recover in line without exiting the |
||||
* surrounding rule. |
||||
*/ |
||||
public void syntaxError(Recognizer<?, ?> recognizer, |
||||
Object offendingSymbol, |
||||
int line, |
||||
int charPositionInLine, |
||||
String msg, |
||||
RecognitionException e); |
||||
|
||||
/** |
||||
* This method is called by the parser when a full-context prediction |
||||
* results in an ambiguity. |
||||
* |
||||
* <p>Each full-context prediction which does not result in a syntax error |
||||
* will call either {@link #reportContextSensitivity} or |
||||
* {@link #reportAmbiguity}.</p> |
||||
* |
||||
* <p>When {@code ambigAlts} is not null, it contains the set of potentially |
||||
* viable alternatives identified by the prediction algorithm. When |
||||
* {@code ambigAlts} is null, use {@link ATNConfigSet#getAlts} to obtain the |
||||
* represented alternatives from the {@code configs} argument.</p> |
||||
* |
||||
* <p>When {@code exact} is {@code true}, <em>all</em> of the potentially |
||||
* viable alternatives are truly viable, i.e. this is reporting an exact |
||||
* ambiguity. When {@code exact} is {@code false}, <em>at least two</em> of |
||||
* the potentially viable alternatives are viable for the current input, but |
||||
* the prediction algorithm terminated as soon as it determined that at |
||||
* least the <em>minimum</em> potentially viable alternative is truly |
||||
* viable.</p> |
||||
* |
||||
* <p>When the {@link PredictionMode#LL_EXACT_AMBIG_DETECTION} prediction |
||||
* mode is used, the parser is required to identify exact ambiguities so |
||||
* {@code exact} will always be {@code true}.</p> |
||||
* |
||||
* <p>This method is not used by lexers.</p> |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @param dfa the DFA for the current decision |
||||
* @param startIndex the input index where the decision started |
||||
* @param stopIndex the input input where the ambiguity was identified |
||||
* @param exact {@code true} if the ambiguity is exactly known, otherwise |
||||
* {@code false}. This is always {@code true} when |
||||
* {@link PredictionMode#LL_EXACT_AMBIG_DETECTION} is used. |
||||
* @param ambigAlts the potentially ambiguous alternatives, or {@code null} |
||||
* to indicate that the potentially ambiguous alternatives are the complete |
||||
* set of represented alternatives in {@code configs} |
||||
* @param configs the ATN configuration set where the ambiguity was |
||||
* identified |
||||
*/ |
||||
void reportAmbiguity(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
boolean exact, |
||||
BitSet ambigAlts, |
||||
ATNConfigSet configs); |
||||
|
||||
/** |
||||
* This method is called when an SLL conflict occurs and the parser is about |
||||
* to use the full context information to make an LL decision. |
||||
* |
||||
* <p>If one or more configurations in {@code configs} contains a semantic |
||||
* predicate, the predicates are evaluated before this method is called. The |
||||
* subset of alternatives which are still viable after predicates are |
||||
* evaluated is reported in {@code conflictingAlts}.</p> |
||||
* |
||||
* <p>This method is not used by lexers.</p> |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @param dfa the DFA for the current decision |
||||
* @param startIndex the input index where the decision started |
||||
* @param stopIndex the input index where the SLL conflict occurred |
||||
* @param conflictingAlts The specific conflicting alternatives. If this is |
||||
* {@code null}, the conflicting alternatives are all alternatives |
||||
* represented in {@code configs}. At the moment, conflictingAlts is non-null |
||||
* (for the reference implementation, but Sam's optimized version can see this |
||||
* as null). |
||||
* @param configs the ATN configuration set where the SLL conflict was |
||||
* detected |
||||
*/ |
||||
void reportAttemptingFullContext(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
BitSet conflictingAlts, |
||||
ATNConfigSet configs); |
||||
|
||||
/** |
||||
* This method is called by the parser when a full-context prediction has a |
||||
* unique result. |
||||
* |
||||
* <p>Each full-context prediction which does not result in a syntax error |
||||
* will call either {@link #reportContextSensitivity} or |
||||
* {@link #reportAmbiguity}.</p> |
||||
* |
||||
* <p>For prediction implementations that only evaluate full-context |
||||
* predictions when an SLL conflict is found (including the default |
||||
* {@link ParserATNSimulator} implementation), this method reports cases |
||||
* where SLL conflicts were resolved to unique full-context predictions, |
||||
* i.e. the decision was context-sensitive. This report does not necessarily |
||||
* indicate a problem, and it may appear even in completely unambiguous |
||||
* grammars.</p> |
||||
* |
||||
* <p>{@code configs} may have more than one represented alternative if the |
||||
* full-context prediction algorithm does not evaluate predicates before |
||||
* beginning the full-context prediction. In all cases, the final prediction |
||||
* is passed as the {@code prediction} argument.</p> |
||||
* |
||||
* <p>Note that the definition of "context sensitivity" in this method |
||||
* differs from the concept in {@link DecisionInfo#contextSensitivities}. |
||||
* This method reports all instances where an SLL conflict occurred but LL |
||||
* parsing produced a unique result, whether or not that unique result |
||||
* matches the minimum alternative in the SLL conflicting set.</p> |
||||
* |
||||
* <p>This method is not used by lexers.</p> |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @param dfa the DFA for the current decision |
||||
* @param startIndex the input index where the decision started |
||||
* @param stopIndex the input index where the context sensitivity was |
||||
* finally determined |
||||
* @param prediction the unambiguous result of the full-context prediction |
||||
* @param configs the ATN configuration set where the unambiguous prediction |
||||
* was determined |
||||
*/ |
||||
void reportContextSensitivity(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
int prediction, |
||||
ATNConfigSet configs); |
||||
} |
@ -1,120 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.tree.ErrorNode; |
||||
|
||||
/** |
||||
* The interface for defining strategies to deal with syntax errors encountered |
||||
* during a parse by ANTLR-generated parsers. We distinguish between three |
||||
* different kinds of errors: |
||||
* |
||||
* <ul> |
||||
* <li>The parser could not figure out which path to take in the ATN (none of |
||||
* the available alternatives could possibly match)</li> |
||||
* <li>The current input does not match what we were looking for</li> |
||||
* <li>A predicate evaluated to false</li> |
||||
* </ul> |
||||
* |
||||
* Implementations of this interface report syntax errors by calling |
||||
* {@link Parser#notifyErrorListeners}. |
||||
* |
||||
* <p>TODO: what to do about lexers</p> |
||||
*/ |
||||
public interface ANTLRErrorStrategy { |
||||
/** |
||||
* Reset the error handler state for the specified {@code recognizer}. |
||||
* @param recognizer the parser instance |
||||
*/ |
||||
void reset(Parser recognizer); |
||||
|
||||
/** |
||||
* This method is called when an unexpected symbol is encountered during an |
||||
* inline match operation, such as {@link Parser#match}. If the error |
||||
* strategy successfully recovers from the match failure, this method |
||||
* returns the {@link Token} instance which should be treated as the |
||||
* successful result of the match. |
||||
* |
||||
* <p>This method handles the consumption of any tokens - the caller should |
||||
* <b>not</b> call {@link Parser#consume} after a successful recovery.</p> |
||||
* |
||||
* <p>Note that the calling code will not report an error if this method |
||||
* returns successfully. The error strategy implementation is responsible |
||||
* for calling {@link Parser#notifyErrorListeners} as appropriate.</p> |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @throws RecognitionException if the error strategy was not able to |
||||
* recover from the unexpected input symbol |
||||
*/ |
||||
Token recoverInline(Parser recognizer) throws RecognitionException; |
||||
|
||||
/** |
||||
* This method is called to recover from exception {@code e}. This method is |
||||
* called after {@link #reportError} by the default exception handler |
||||
* generated for a rule method. |
||||
* |
||||
* @see #reportError |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @param e the recognition exception to recover from |
||||
* @throws RecognitionException if the error strategy could not recover from |
||||
* the recognition exception |
||||
*/ |
||||
void recover(Parser recognizer, RecognitionException e) throws RecognitionException; |
||||
|
||||
/** |
||||
* This method provides the error handler with an opportunity to handle |
||||
* syntactic or semantic errors in the input stream before they result in a |
||||
* {@link RecognitionException}. |
||||
* |
||||
* <p>The generated code currently contains calls to {@link #sync} after |
||||
* entering the decision state of a closure block ({@code (...)*} or |
||||
* {@code (...)+}).</p> |
||||
* |
||||
* <p>For an implementation based on Jim Idle's "magic sync" mechanism, see |
||||
* {@link DefaultErrorStrategy#sync}.</p> |
||||
* |
||||
* @see DefaultErrorStrategy#sync |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @throws RecognitionException if an error is detected by the error |
||||
* strategy but cannot be automatically recovered at the current state in |
||||
* the parsing process |
||||
*/ |
||||
void sync(Parser recognizer) throws RecognitionException; |
||||
|
||||
/** |
||||
* Tests whether or not {@code recognizer} is in the process of recovering |
||||
* from an error. In error recovery mode, {@link Parser#consume} adds |
||||
* symbols to the parse tree by calling |
||||
* {@link Parser#createErrorNode(ParserRuleContext, Token)} then |
||||
* {@link ParserRuleContext#addErrorNode(ErrorNode)} instead of |
||||
* {@link Parser#createTerminalNode(ParserRuleContext, Token)}. |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @return {@code true} if the parser is currently recovering from a parse |
||||
* error, otherwise {@code false} |
||||
*/ |
||||
boolean inErrorRecoveryMode(Parser recognizer); |
||||
|
||||
/** |
||||
* This method is called by when the parser successfully matches an input |
||||
* symbol. |
||||
* |
||||
* @param recognizer the parser instance |
||||
*/ |
||||
void reportMatch(Parser recognizer); |
||||
|
||||
/** |
||||
* Report any kind of {@link RecognitionException}. This method is called by |
||||
* the default exception handler generated for a rule method. |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @param e the recognition exception to report |
||||
*/ |
||||
void reportError(Parser recognizer, RecognitionException e); |
||||
} |
@ -1,41 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Utils; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* This is an {@link ANTLRInputStream} that is loaded from a file all at once |
||||
* when you construct the object. |
||||
* |
||||
* @deprecated as of 4.7 Please use {@link CharStreams} interface. |
||||
*/ |
||||
public class ANTLRFileStream extends ANTLRInputStream { |
||||
protected String fileName; |
||||
|
||||
public ANTLRFileStream(String fileName) throws IOException { |
||||
this(fileName, null); |
||||
} |
||||
|
||||
public ANTLRFileStream(String fileName, String encoding) throws IOException { |
||||
this.fileName = fileName; |
||||
load(fileName, encoding); |
||||
} |
||||
|
||||
public void load(String fileName, String encoding) |
||||
throws IOException |
||||
{ |
||||
data = Utils.readFile(fileName, encoding); |
||||
this.n = data.length; |
||||
} |
||||
|
||||
@Override |
||||
public String getSourceName() { |
||||
return fileName; |
||||
} |
||||
} |
@ -1,228 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.InputStreamReader; |
||||
import java.io.Reader; |
||||
import java.util.Arrays; |
||||
|
||||
/** |
||||
* Vacuum all input from a {@link Reader}/{@link InputStream} and then treat it |
||||
* like a {@code char[]} buffer. Can also pass in a {@link String} or |
||||
* {@code char[]} to use. |
||||
* |
||||
* <p>If you need encoding, pass in stream/reader with correct encoding.</p> |
||||
* |
||||
* @deprecated as of 4.7 Please use {@link CharStreams} interface. |
||||
*/ |
||||
public class ANTLRInputStream implements CharStream { |
||||
public static final int READ_BUFFER_SIZE = 1024; |
||||
public static final int INITIAL_BUFFER_SIZE = 1024; |
||||
|
||||
/** The data being scanned */ |
||||
protected char[] data; |
||||
|
||||
/** How many characters are actually in the buffer */ |
||||
protected int n; |
||||
|
||||
/** 0..n-1 index into string of next char */ |
||||
protected int p=0; |
||||
|
||||
/** What is name or source of this char stream? */ |
||||
public String name; |
||||
|
||||
public ANTLRInputStream() { } |
||||
|
||||
/** Copy data in string to a local char array */ |
||||
public ANTLRInputStream(String input) { |
||||
this.data = input.toCharArray(); |
||||
this.n = input.length(); |
||||
} |
||||
|
||||
/** This is the preferred constructor for strings as no data is copied */ |
||||
public ANTLRInputStream(char[] data, int numberOfActualCharsInArray) { |
||||
this.data = data; |
||||
this.n = numberOfActualCharsInArray; |
||||
} |
||||
|
||||
public ANTLRInputStream(Reader r) throws IOException { |
||||
this(r, INITIAL_BUFFER_SIZE, READ_BUFFER_SIZE); |
||||
} |
||||
|
||||
public ANTLRInputStream(Reader r, int initialSize) throws IOException { |
||||
this(r, initialSize, READ_BUFFER_SIZE); |
||||
} |
||||
|
||||
public ANTLRInputStream(Reader r, int initialSize, int readChunkSize) throws IOException { |
||||
load(r, initialSize, readChunkSize); |
||||
} |
||||
|
||||
public ANTLRInputStream(InputStream input) throws IOException { |
||||
this(new InputStreamReader(input), INITIAL_BUFFER_SIZE); |
||||
} |
||||
|
||||
public ANTLRInputStream(InputStream input, int initialSize) throws IOException { |
||||
this(new InputStreamReader(input), initialSize); |
||||
} |
||||
|
||||
public ANTLRInputStream(InputStream input, int initialSize, int readChunkSize) throws IOException { |
||||
this(new InputStreamReader(input), initialSize, readChunkSize); |
||||
} |
||||
|
||||
public void load(Reader r, int size, int readChunkSize) |
||||
throws IOException |
||||
{ |
||||
if ( r==null ) { |
||||
return; |
||||
} |
||||
if ( size<=0 ) { |
||||
size = INITIAL_BUFFER_SIZE; |
||||
} |
||||
if ( readChunkSize<=0 ) { |
||||
readChunkSize = READ_BUFFER_SIZE; |
||||
} |
||||
// System.out.println("load "+size+" in chunks of "+readChunkSize);
|
||||
try { |
||||
// alloc initial buffer size.
|
||||
data = new char[size]; |
||||
// read all the data in chunks of readChunkSize
|
||||
int numRead=0; |
||||
int p = 0; |
||||
do { |
||||
if ( p+readChunkSize > data.length ) { // overflow?
|
||||
// System.out.println("### overflow p="+p+", data.length="+data.length);
|
||||
data = Arrays.copyOf(data, data.length * 2); |
||||
} |
||||
numRead = r.read(data, p, readChunkSize); |
||||
// System.out.println("read "+numRead+" chars; p was "+p+" is now "+(p+numRead));
|
||||
p += numRead; |
||||
} while (numRead!=-1); // while not EOF
|
||||
// set the actual size of the data available;
|
||||
// EOF subtracted one above in p+=numRead; add one back
|
||||
n = p+1; |
||||
//System.out.println("n="+n);
|
||||
} |
||||
finally { |
||||
r.close(); |
||||
} |
||||
} |
||||
|
||||
/** Reset the stream so that it's in the same state it was |
||||
* when the object was created *except* the data array is not |
||||
* touched. |
||||
*/ |
||||
public void reset() { |
||||
p = 0; |
||||
} |
||||
|
||||
@Override |
||||
public void consume() { |
||||
if (p >= n) { |
||||
assert LA(1) == IntStream.EOF; |
||||
throw new IllegalStateException("cannot consume EOF"); |
||||
} |
||||
|
||||
//System.out.println("prev p="+p+", c="+(char)data[p]);
|
||||
if ( p < n ) { |
||||
p++; |
||||
//System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')");
|
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int LA(int i) { |
||||
if ( i==0 ) { |
||||
return 0; // undefined
|
||||
} |
||||
if ( i<0 ) { |
||||
i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
|
||||
if ( (p+i-1) < 0 ) { |
||||
return IntStream.EOF; // invalid; no char before first char
|
||||
} |
||||
} |
||||
|
||||
if ( (p+i-1) >= n ) { |
||||
//System.out.println("char LA("+i+")=EOF; p="+p);
|
||||
return IntStream.EOF; |
||||
} |
||||
//System.out.println("char LA("+i+")="+(char)data[p+i-1]+"; p="+p);
|
||||
//System.out.println("LA("+i+"); p="+p+" n="+n+" data.length="+data.length);
|
||||
return data[p+i-1]; |
||||
} |
||||
|
||||
public int LT(int i) { |
||||
return LA(i); |
||||
} |
||||
|
||||
/** Return the current input symbol index 0..n where n indicates the |
||||
* last symbol has been read. The index is the index of char to |
||||
* be returned from LA(1). |
||||
*/ |
||||
@Override |
||||
public int index() { |
||||
return p; |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return n; |
||||
} |
||||
|
||||
/** mark/release do nothing; we have entire buffer */ |
||||
@Override |
||||
public int mark() { |
||||
return -1; |
||||
} |
||||
|
||||
@Override |
||||
public void release(int marker) { |
||||
} |
||||
|
||||
/** consume() ahead until p==index; can't just set p=index as we must |
||||
* update line and charPositionInLine. If we seek backwards, just set p |
||||
*/ |
||||
@Override |
||||
public void seek(int index) { |
||||
if ( index<=p ) { |
||||
p = index; // just jump; don't update stream state (line, ...)
|
||||
return; |
||||
} |
||||
// seek forward, consume until p hits index or n (whichever comes first)
|
||||
index = Math.min(index, n); |
||||
while ( p<index ) { |
||||
consume(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public String getText(Interval interval) { |
||||
int start = interval.a; |
||||
int stop = interval.b; |
||||
if ( stop >= n ) stop = n-1; |
||||
int count = stop - start + 1; |
||||
if ( start >= n ) return ""; |
||||
// System.err.println("data: "+Arrays.toString(data)+", n="+n+
|
||||
// ", start="+start+
|
||||
// ", stop="+stop);
|
||||
return new String(data, start, count); |
||||
} |
||||
|
||||
@Override |
||||
public String getSourceName() { |
||||
if (name == null || name.isEmpty()) { |
||||
return UNKNOWN_SOURCE_NAME; |
||||
} |
||||
|
||||
return name; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { return new String(data); } |
||||
} |
@ -1,72 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.ParseCancellationException; |
||||
|
||||
/** |
||||
* This implementation of {@link ANTLRErrorStrategy} responds to syntax errors |
||||
* by immediately canceling the parse operation with a |
||||
* {@link ParseCancellationException}. The implementation ensures that the |
||||
* {@link ParserRuleContext#exception} field is set for all parse tree nodes |
||||
* that were not completed prior to encountering the error. |
||||
* |
||||
* <p> |
||||
* This error strategy is useful in the following scenarios.</p> |
||||
* |
||||
* <ul> |
||||
* <li><strong>Two-stage parsing:</strong> This error strategy allows the first |
||||
* stage of two-stage parsing to immediately terminate if an error is |
||||
* encountered, and immediately fall back to the second stage. In addition to |
||||
* avoiding wasted work by attempting to recover from errors here, the empty |
||||
* implementation of {@link BailErrorStrategy#sync} improves the performance of |
||||
* the first stage.</li> |
||||
* <li><strong>Silent validation:</strong> When syntax errors are not being |
||||
* reported or logged, and the parse result is simply ignored if errors occur, |
||||
* the {@link BailErrorStrategy} avoids wasting work on recovering from errors |
||||
* when the result will be ignored either way.</li> |
||||
* </ul> |
||||
* |
||||
* <p> |
||||
* {@code myparser.setErrorHandler(new BailErrorStrategy());}</p> |
||||
* |
||||
* @see Parser#setErrorHandler(ANTLRErrorStrategy) |
||||
*/ |
||||
public class BailErrorStrategy extends DefaultErrorStrategy { |
||||
/** Instead of recovering from exception {@code e}, re-throw it wrapped |
||||
* in a {@link ParseCancellationException} so it is not caught by the |
||||
* rule function catches. Use {@link Exception#getCause()} to get the |
||||
* original {@link RecognitionException}. |
||||
*/ |
||||
@Override |
||||
public void recover(Parser recognizer, RecognitionException e) { |
||||
for (ParserRuleContext context = recognizer.getContext(); context != null; context = context.getParent()) { |
||||
context.exception = e; |
||||
} |
||||
|
||||
throw new ParseCancellationException(e); |
||||
} |
||||
|
||||
/** Make sure we don't attempt to recover inline; if the parser |
||||
* successfully recovers, it won't throw an exception. |
||||
*/ |
||||
@Override |
||||
public Token recoverInline(Parser recognizer) |
||||
throws RecognitionException |
||||
{ |
||||
InputMismatchException e = new InputMismatchException(recognizer); |
||||
for (ParserRuleContext context = recognizer.getContext(); context != null; context = context.getParent()) { |
||||
context.exception = e; |
||||
} |
||||
|
||||
throw new ParseCancellationException(e); |
||||
} |
||||
|
||||
/** Make sure we don't attempt to recover from problems in subrules. */ |
||||
@Override |
||||
public void sync(Parser recognizer) { } |
||||
} |
@ -1,61 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNConfigSet; |
||||
import com.fr.third.org.antlr.v4.runtime.dfa.DFA; |
||||
|
||||
import java.util.BitSet; |
||||
|
||||
/** |
||||
* Provides an empty default implementation of {@link ANTLRErrorListener}. The |
||||
* default implementation of each method does nothing, but can be overridden as |
||||
* necessary. |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public class BaseErrorListener implements ANTLRErrorListener { |
||||
@Override |
||||
public void syntaxError(Recognizer<?, ?> recognizer, |
||||
Object offendingSymbol, |
||||
int line, |
||||
int charPositionInLine, |
||||
String msg, |
||||
RecognitionException e) |
||||
{ |
||||
} |
||||
|
||||
@Override |
||||
public void reportAmbiguity(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
boolean exact, |
||||
BitSet ambigAlts, |
||||
ATNConfigSet configs) |
||||
{ |
||||
} |
||||
|
||||
@Override |
||||
public void reportAttemptingFullContext(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
BitSet conflictingAlts, |
||||
ATNConfigSet configs) |
||||
{ |
||||
} |
||||
|
||||
@Override |
||||
public void reportContextSensitivity(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
int prediction, |
||||
ATNConfigSet configs) |
||||
{ |
||||
} |
||||
} |
@ -1,491 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashSet; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* This implementation of {@link TokenStream} loads tokens from a |
||||
* {@link TokenSource} on-demand, and places the tokens in a buffer to provide |
||||
* access to any previous token by index. |
||||
* |
||||
* <p> |
||||
* This token stream ignores the value of {@link Token#getChannel}. If your |
||||
* parser requires the token stream filter tokens to only those on a particular |
||||
* channel, such as {@link Token#DEFAULT_CHANNEL} or |
||||
* {@link Token#HIDDEN_CHANNEL}, use a filtering token stream such a |
||||
* {@link CommonTokenStream}.</p> |
||||
*/ |
||||
public class BufferedTokenStream implements TokenStream { |
||||
/** |
||||
* The {@link TokenSource} from which tokens for this stream are fetched. |
||||
*/ |
||||
protected TokenSource tokenSource; |
||||
|
||||
/** |
||||
* A collection of all tokens fetched from the token source. The list is |
||||
* considered a complete view of the input once {@link #fetchedEOF} is set |
||||
* to {@code true}. |
||||
*/ |
||||
protected List<Token> tokens = new ArrayList<Token>(100); |
||||
|
||||
/** |
||||
* The index into {@link #tokens} of the current token (next token to |
||||
* {@link #consume}). {@link #tokens}{@code [}{@link #p}{@code ]} should be |
||||
* {@link #LT LT(1)}. |
||||
* |
||||
* <p>This field is set to -1 when the stream is first constructed or when |
||||
* {@link #setTokenSource} is called, indicating that the first token has |
||||
* not yet been fetched from the token source. For additional information, |
||||
* see the documentation of {@link IntStream} for a description of |
||||
* Initializing Methods.</p> |
||||
*/ |
||||
protected int p = -1; |
||||
|
||||
/** |
||||
* Indicates whether the {@link Token#EOF} token has been fetched from |
||||
* {@link #tokenSource} and added to {@link #tokens}. This field improves |
||||
* performance for the following cases: |
||||
* |
||||
* <ul> |
||||
* <li>{@link #consume}: The lookahead check in {@link #consume} to prevent |
||||
* consuming the EOF symbol is optimized by checking the values of |
||||
* {@link #fetchedEOF} and {@link #p} instead of calling {@link #LA}.</li> |
||||
* <li>{@link #fetch}: The check to prevent adding multiple EOF symbols into |
||||
* {@link #tokens} is trivial with this field.</li> |
||||
* <ul> |
||||
*/ |
||||
protected boolean fetchedEOF; |
||||
|
||||
public BufferedTokenStream(TokenSource tokenSource) { |
||||
if (tokenSource == null) { |
||||
throw new NullPointerException("tokenSource cannot be null"); |
||||
} |
||||
this.tokenSource = tokenSource; |
||||
} |
||||
|
||||
@Override |
||||
public TokenSource getTokenSource() { return tokenSource; } |
||||
|
||||
@Override |
||||
public int index() { return p; } |
||||
|
||||
@Override |
||||
public int mark() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public void release(int marker) { |
||||
// no resources to release
|
||||
} |
||||
|
||||
/** |
||||
* This method resets the token stream back to the first token in the |
||||
* buffer. It is equivalent to calling {@link #seek}{@code (0)}. |
||||
* |
||||
* @see #setTokenSource(TokenSource) |
||||
* @deprecated Use {@code seek(0)} instead. |
||||
*/ |
||||
@Deprecated |
||||
public void reset() { |
||||
seek(0); |
||||
} |
||||
|
||||
@Override |
||||
public void seek(int index) { |
||||
lazyInit(); |
||||
p = adjustSeekIndex(index); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { return tokens.size(); } |
||||
|
||||
@Override |
||||
public void consume() { |
||||
boolean skipEofCheck; |
||||
if (p >= 0) { |
||||
if (fetchedEOF) { |
||||
// the last token in tokens is EOF. skip check if p indexes any
|
||||
// fetched token except the last.
|
||||
skipEofCheck = p < tokens.size() - 1; |
||||
} |
||||
else { |
||||
// no EOF token in tokens. skip check if p indexes a fetched token.
|
||||
skipEofCheck = p < tokens.size(); |
||||
} |
||||
} |
||||
else { |
||||
// not yet initialized
|
||||
skipEofCheck = false; |
||||
} |
||||
|
||||
if (!skipEofCheck && LA(1) == EOF) { |
||||
throw new IllegalStateException("cannot consume EOF"); |
||||
} |
||||
|
||||
if (sync(p + 1)) { |
||||
p = adjustSeekIndex(p + 1); |
||||
} |
||||
} |
||||
|
||||
/** Make sure index {@code i} in tokens has a token. |
||||
* |
||||
* @return {@code true} if a token is located at index {@code i}, otherwise |
||||
* {@code false}. |
||||
* @see #get(int i) |
||||
*/ |
||||
protected boolean sync(int i) { |
||||
assert i >= 0; |
||||
int n = i - tokens.size() + 1; // how many more elements we need?
|
||||
//System.out.println("sync("+i+") needs "+n);
|
||||
if ( n > 0 ) { |
||||
int fetched = fetch(n); |
||||
return fetched >= n; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** Add {@code n} elements to buffer. |
||||
* |
||||
* @return The actual number of elements added to the buffer. |
||||
*/ |
||||
protected int fetch(int n) { |
||||
if (fetchedEOF) { |
||||
return 0; |
||||
} |
||||
|
||||
for (int i = 0; i < n; i++) { |
||||
Token t = tokenSource.nextToken(); |
||||
if ( t instanceof WritableToken ) { |
||||
((WritableToken)t).setTokenIndex(tokens.size()); |
||||
} |
||||
tokens.add(t); |
||||
if ( t.getType()==Token.EOF ) { |
||||
fetchedEOF = true; |
||||
return i + 1; |
||||
} |
||||
} |
||||
|
||||
return n; |
||||
} |
||||
|
||||
@Override |
||||
public Token get(int i) { |
||||
if ( i < 0 || i >= tokens.size() ) { |
||||
throw new IndexOutOfBoundsException("token index "+i+" out of range 0.."+(tokens.size()-1)); |
||||
} |
||||
return tokens.get(i); |
||||
} |
||||
|
||||
/** Get all tokens from start..stop inclusively */ |
||||
public List<Token> get(int start, int stop) { |
||||
if ( start<0 || stop<0 ) return null; |
||||
lazyInit(); |
||||
List<Token> subset = new ArrayList<Token>(); |
||||
if ( stop>=tokens.size() ) stop = tokens.size()-1; |
||||
for (int i = start; i <= stop; i++) { |
||||
Token t = tokens.get(i); |
||||
if ( t.getType()==Token.EOF ) break; |
||||
subset.add(t); |
||||
} |
||||
return subset; |
||||
} |
||||
|
||||
@Override |
||||
public int LA(int i) { return LT(i).getType(); } |
||||
|
||||
protected Token LB(int k) { |
||||
if ( (p-k)<0 ) return null; |
||||
return tokens.get(p-k); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Token LT(int k) { |
||||
lazyInit(); |
||||
if ( k==0 ) return null; |
||||
if ( k < 0 ) return LB(-k); |
||||
|
||||
int i = p + k - 1; |
||||
sync(i); |
||||
if ( i >= tokens.size() ) { // return EOF token
|
||||
// EOF must be last token
|
||||
return tokens.get(tokens.size()-1); |
||||
} |
||||
// if ( i>range ) range = i;
|
||||
return tokens.get(i); |
||||
} |
||||
|
||||
/** |
||||
* Allowed derived classes to modify the behavior of operations which change |
||||
* the current stream position by adjusting the target token index of a seek |
||||
* operation. The default implementation simply returns {@code i}. If an |
||||
* exception is thrown in this method, the current stream index should not be |
||||
* changed. |
||||
* |
||||
* <p>For example, {@link CommonTokenStream} overrides this method to ensure that |
||||
* the seek target is always an on-channel token.</p> |
||||
* |
||||
* @param i The target token index. |
||||
* @return The adjusted target token index. |
||||
*/ |
||||
protected int adjustSeekIndex(int i) { |
||||
return i; |
||||
} |
||||
|
||||
protected final void lazyInit() { |
||||
if (p == -1) { |
||||
setup(); |
||||
} |
||||
} |
||||
|
||||
protected void setup() { |
||||
sync(0); |
||||
p = adjustSeekIndex(0); |
||||
} |
||||
|
||||
/** Reset this token stream by setting its token source. */ |
||||
public void setTokenSource(TokenSource tokenSource) { |
||||
this.tokenSource = tokenSource; |
||||
tokens.clear(); |
||||
p = -1; |
||||
fetchedEOF = false; |
||||
} |
||||
|
||||
public List<Token> getTokens() { return tokens; } |
||||
|
||||
public List<Token> getTokens(int start, int stop) { |
||||
return getTokens(start, stop, null); |
||||
} |
||||
|
||||
/** Given a start and stop index, return a List of all tokens in |
||||
* the token type BitSet. Return null if no tokens were found. This |
||||
* method looks at both on and off channel tokens. |
||||
*/ |
||||
public List<Token> getTokens(int start, int stop, Set<Integer> types) { |
||||
lazyInit(); |
||||
if ( start<0 || stop>=tokens.size() || |
||||
stop<0 || start>=tokens.size() ) |
||||
{ |
||||
throw new IndexOutOfBoundsException("start "+start+" or stop "+stop+ |
||||
" not in 0.."+(tokens.size()-1)); |
||||
} |
||||
if ( start>stop ) return null; |
||||
|
||||
// list = tokens[start:stop]:{T t, t.getType() in types}
|
||||
List<Token> filteredTokens = new ArrayList<Token>(); |
||||
for (int i=start; i<=stop; i++) { |
||||
Token t = tokens.get(i); |
||||
if ( types==null || types.contains(t.getType()) ) { |
||||
filteredTokens.add(t); |
||||
} |
||||
} |
||||
if ( filteredTokens.isEmpty() ) { |
||||
filteredTokens = null; |
||||
} |
||||
return filteredTokens; |
||||
} |
||||
|
||||
public List<Token> getTokens(int start, int stop, int ttype) { |
||||
HashSet<Integer> s = new HashSet<Integer>(ttype); |
||||
s.add(ttype); |
||||
return getTokens(start,stop, s); |
||||
} |
||||
|
||||
/** |
||||
* Given a starting index, return the index of the next token on channel. |
||||
* Return {@code i} if {@code tokens[i]} is on channel. Return the index of |
||||
* the EOF token if there are no tokens on channel between {@code i} and |
||||
* EOF. |
||||
*/ |
||||
protected int nextTokenOnChannel(int i, int channel) { |
||||
sync(i); |
||||
if (i >= size()) { |
||||
return size() - 1; |
||||
} |
||||
|
||||
Token token = tokens.get(i); |
||||
while ( token.getChannel()!=channel ) { |
||||
if ( token.getType()==Token.EOF ) { |
||||
return i; |
||||
} |
||||
|
||||
i++; |
||||
sync(i); |
||||
token = tokens.get(i); |
||||
} |
||||
|
||||
return i; |
||||
} |
||||
|
||||
/** |
||||
* Given a starting index, return the index of the previous token on |
||||
* channel. Return {@code i} if {@code tokens[i]} is on channel. Return -1 |
||||
* if there are no tokens on channel between {@code i} and 0. |
||||
* |
||||
* <p> |
||||
* If {@code i} specifies an index at or after the EOF token, the EOF token |
||||
* index is returned. This is due to the fact that the EOF token is treated |
||||
* as though it were on every channel.</p> |
||||
*/ |
||||
protected int previousTokenOnChannel(int i, int channel) { |
||||
sync(i); |
||||
if (i >= size()) { |
||||
// the EOF token is on every channel
|
||||
return size() - 1; |
||||
} |
||||
|
||||
while (i >= 0) { |
||||
Token token = tokens.get(i); |
||||
if (token.getType() == Token.EOF || token.getChannel() == channel) { |
||||
return i; |
||||
} |
||||
|
||||
i--; |
||||
} |
||||
|
||||
return i; |
||||
} |
||||
|
||||
/** Collect all tokens on specified channel to the right of |
||||
* the current token up until we see a token on DEFAULT_TOKEN_CHANNEL or |
||||
* EOF. If channel is -1, find any non default channel token. |
||||
*/ |
||||
public List<Token> getHiddenTokensToRight(int tokenIndex, int channel) { |
||||
lazyInit(); |
||||
if ( tokenIndex<0 || tokenIndex>=tokens.size() ) { |
||||
throw new IndexOutOfBoundsException(tokenIndex+" not in 0.."+(tokens.size()-1)); |
||||
} |
||||
|
||||
int nextOnChannel = |
||||
nextTokenOnChannel(tokenIndex + 1, Lexer.DEFAULT_TOKEN_CHANNEL); |
||||
int to; |
||||
int from = tokenIndex+1; |
||||
// if none onchannel to right, nextOnChannel=-1 so set to = last token
|
||||
if ( nextOnChannel == -1 ) to = size()-1; |
||||
else to = nextOnChannel; |
||||
|
||||
return filterForChannel(from, to, channel); |
||||
} |
||||
|
||||
/** Collect all hidden tokens (any off-default channel) to the right of |
||||
* the current token up until we see a token on DEFAULT_TOKEN_CHANNEL |
||||
* or EOF. |
||||
*/ |
||||
public List<Token> getHiddenTokensToRight(int tokenIndex) { |
||||
return getHiddenTokensToRight(tokenIndex, -1); |
||||
} |
||||
|
||||
/** Collect all tokens on specified channel to the left of |
||||
* the current token up until we see a token on DEFAULT_TOKEN_CHANNEL. |
||||
* If channel is -1, find any non default channel token. |
||||
*/ |
||||
public List<Token> getHiddenTokensToLeft(int tokenIndex, int channel) { |
||||
lazyInit(); |
||||
if ( tokenIndex<0 || tokenIndex>=tokens.size() ) { |
||||
throw new IndexOutOfBoundsException(tokenIndex+" not in 0.."+(tokens.size()-1)); |
||||
} |
||||
|
||||
if (tokenIndex == 0) { |
||||
// obviously no tokens can appear before the first token
|
||||
return null; |
||||
} |
||||
|
||||
int prevOnChannel = |
||||
previousTokenOnChannel(tokenIndex - 1, Lexer.DEFAULT_TOKEN_CHANNEL); |
||||
if ( prevOnChannel == tokenIndex - 1 ) return null; |
||||
// if none onchannel to left, prevOnChannel=-1 then from=0
|
||||
int from = prevOnChannel+1; |
||||
int to = tokenIndex-1; |
||||
|
||||
return filterForChannel(from, to, channel); |
||||
} |
||||
|
||||
/** Collect all hidden tokens (any off-default channel) to the left of |
||||
* the current token up until we see a token on DEFAULT_TOKEN_CHANNEL. |
||||
*/ |
||||
public List<Token> getHiddenTokensToLeft(int tokenIndex) { |
||||
return getHiddenTokensToLeft(tokenIndex, -1); |
||||
} |
||||
|
||||
protected List<Token> filterForChannel(int from, int to, int channel) { |
||||
List<Token> hidden = new ArrayList<Token>(); |
||||
for (int i=from; i<=to; i++) { |
||||
Token t = tokens.get(i); |
||||
if ( channel==-1 ) { |
||||
if ( t.getChannel()!= Lexer.DEFAULT_TOKEN_CHANNEL ) hidden.add(t); |
||||
} |
||||
else { |
||||
if ( t.getChannel()==channel ) hidden.add(t); |
||||
} |
||||
} |
||||
if ( hidden.size()==0 ) return null; |
||||
return hidden; |
||||
} |
||||
|
||||
@Override |
||||
public String getSourceName() { return tokenSource.getSourceName(); } |
||||
|
||||
/** Get the text of all tokens in this buffer. */ |
||||
|
||||
@Override |
||||
public String getText() { |
||||
return getText(Interval.of(0,size()-1)); |
||||
} |
||||
|
||||
@Override |
||||
public String getText(Interval interval) { |
||||
int start = interval.a; |
||||
int stop = interval.b; |
||||
if ( start<0 || stop<0 ) return ""; |
||||
fill(); |
||||
if ( stop>=tokens.size() ) stop = tokens.size()-1; |
||||
|
||||
StringBuilder buf = new StringBuilder(); |
||||
for (int i = start; i <= stop; i++) { |
||||
Token t = tokens.get(i); |
||||
if ( t.getType()==Token.EOF ) break; |
||||
buf.append(t.getText()); |
||||
} |
||||
return buf.toString(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String getText(RuleContext ctx) { |
||||
return getText(ctx.getSourceInterval()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String getText(Token start, Token stop) { |
||||
if ( start!=null && stop!=null ) { |
||||
return getText(Interval.of(start.getTokenIndex(), stop.getTokenIndex())); |
||||
} |
||||
|
||||
return ""; |
||||
} |
||||
|
||||
/** Get all tokens from lexer until EOF */ |
||||
public void fill() { |
||||
lazyInit(); |
||||
final int blockSize = 1000; |
||||
while (true) { |
||||
int fetched = fetch(blockSize); |
||||
if (fetched < blockSize) { |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,30 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
|
||||
/** A source of characters for an ANTLR lexer. */ |
||||
public interface CharStream extends IntStream { |
||||
/** |
||||
* This method returns the text for a range of characters within this input |
||||
* stream. This method is guaranteed to not throw an exception if the |
||||
* specified {@code interval} lies entirely within a marked range. For more |
||||
* information about marked ranges, see {@link IntStream#mark}. |
||||
* |
||||
* @param interval an interval within the stream |
||||
* @return the text of the specified interval |
||||
* |
||||
* @throws NullPointerException if {@code interval} is {@code null} |
||||
* @throws IllegalArgumentException if {@code interval.a < 0}, or if |
||||
* {@code interval.b < interval.a - 1}, or if {@code interval.b} lies at or |
||||
* past the end of the stream |
||||
* @throws UnsupportedOperationException if the stream does not support |
||||
* getting the text of the specified interval |
||||
*/ |
||||
public String getText(Interval interval); |
||||
} |
@ -1,306 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.Reader; |
||||
import java.nio.ByteBuffer; |
||||
import java.nio.CharBuffer; |
||||
import java.nio.channels.Channels; |
||||
import java.nio.channels.ReadableByteChannel; |
||||
import java.nio.charset.Charset; |
||||
import java.nio.charset.CharsetDecoder; |
||||
import java.nio.charset.CoderResult; |
||||
import java.nio.charset.CodingErrorAction; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Path; |
||||
import java.nio.file.Paths; |
||||
|
||||
/** This class represents the primary interface for creating {@link CharStream}s |
||||
* from a variety of sources as of 4.7. The motivation was to support |
||||
* Unicode code points > U+FFFF. {@link ANTLRInputStream} and |
||||
* {@link ANTLRFileStream} are now deprecated in favor of the streams created |
||||
* by this interface. |
||||
* |
||||
* DEPRECATED: {@code new ANTLRFileStream("myinputfile")} |
||||
* NEW: {@code CharStreams.fromFileName("myinputfile")} |
||||
* |
||||
* WARNING: If you use both the deprecated and the new streams, you will see |
||||
* a nontrivial performance degradation. This speed hit is because the |
||||
* {@link Lexer}'s internal code goes from a monomorphic to megamorphic |
||||
* dynamic dispatch to get characters from the input stream. Java's |
||||
* on-the-fly compiler (JIT) is unable to perform the same optimizations |
||||
* so stick with either the old or the new streams, if performance is |
||||
* a primary concern. See the extreme debugging and spelunking |
||||
* needed to identify this issue in our timing rig: |
||||
* |
||||
* https://github.com/antlr/antlr4/pull/1781
|
||||
* |
||||
* The ANTLR character streams still buffer all the input when you create |
||||
* the stream, as they have done for ~20 years. If you need unbuffered |
||||
* access, please note that it becomes challenging to create |
||||
* parse trees. The parse tree has to point to tokens which will either |
||||
* point into a stale location in an unbuffered stream or you have to copy |
||||
* the characters out of the buffer into the token. That defeats the purpose |
||||
* of unbuffered input. Per the ANTLR book, unbuffered streams are primarily |
||||
* useful for processing infinite streams *during the parse.* |
||||
* |
||||
* The new streams also use 8-bit buffers when possible so this new |
||||
* interface supports character streams that use half as much memory |
||||
* as the old {@link ANTLRFileStream}, which assumed 16-bit characters. |
||||
* |
||||
* A big shout out to Ben Hamilton (github bhamiltoncx) for his superhuman |
||||
* efforts across all targets to get true Unicode 3.1 support for U+10FFFF. |
||||
* |
||||
* @since 4.7 |
||||
*/ |
||||
public final class CharStreams { |
||||
private static final int DEFAULT_BUFFER_SIZE = 4096; |
||||
|
||||
// Utility class; do not construct.
|
||||
private CharStreams() { } |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given a path to a UTF-8 |
||||
* encoded file on disk. |
||||
* |
||||
* Reads the entire contents of the file into the result before returning. |
||||
*/ |
||||
public static CharStream fromPath(Path path) throws IOException { |
||||
return fromPath(path, StandardCharsets.UTF_8); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given a path to a file on disk and the |
||||
* charset of the bytes contained in the file. |
||||
* |
||||
* Reads the entire contents of the file into the result before returning. |
||||
*/ |
||||
public static CharStream fromPath(Path path, Charset charset) throws IOException { |
||||
long size = Files.size(path); |
||||
try (ReadableByteChannel channel = Files.newByteChannel(path)) { |
||||
return fromChannel( |
||||
channel, |
||||
charset, |
||||
DEFAULT_BUFFER_SIZE, |
||||
CodingErrorAction.REPLACE, |
||||
path.toString(), |
||||
size); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given a string containing a |
||||
* path to a UTF-8 file on disk. |
||||
* |
||||
* Reads the entire contents of the file into the result before returning. |
||||
*/ |
||||
public static CharStream fromFileName(String fileName) throws IOException { |
||||
return fromPath(Paths.get(fileName), StandardCharsets.UTF_8); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given a string containing a |
||||
* path to a file on disk and the charset of the bytes |
||||
* contained in the file. |
||||
* |
||||
* Reads the entire contents of the file into the result before returning. |
||||
*/ |
||||
public static CharStream fromFileName(String fileName, Charset charset) throws IOException { |
||||
return fromPath(Paths.get(fileName), charset); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given an opened {@link InputStream} |
||||
* containing UTF-8 bytes. |
||||
* |
||||
* Reads the entire contents of the {@code InputStream} into |
||||
* the result before returning, then closes the {@code InputStream}. |
||||
*/ |
||||
public static CharStream fromStream(InputStream is) throws IOException { |
||||
return fromStream(is, StandardCharsets.UTF_8); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given an opened {@link InputStream} and the |
||||
* charset of the bytes contained in the stream. |
||||
* |
||||
* Reads the entire contents of the {@code InputStream} into |
||||
* the result before returning, then closes the {@code InputStream}. |
||||
*/ |
||||
public static CharStream fromStream(InputStream is, Charset charset) throws IOException { |
||||
return fromStream(is, charset, -1); |
||||
} |
||||
|
||||
public static CharStream fromStream(InputStream is, Charset charset, long inputSize) throws IOException { |
||||
try (ReadableByteChannel channel = Channels.newChannel(is)) { |
||||
return fromChannel( |
||||
channel, |
||||
charset, |
||||
DEFAULT_BUFFER_SIZE, |
||||
CodingErrorAction.REPLACE, |
||||
IntStream.UNKNOWN_SOURCE_NAME, |
||||
inputSize); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given an opened {@link ReadableByteChannel} |
||||
* containing UTF-8 bytes. |
||||
* |
||||
* Reads the entire contents of the {@code channel} into |
||||
* the result before returning, then closes the {@code channel}. |
||||
*/ |
||||
public static CharStream fromChannel(ReadableByteChannel channel) throws IOException { |
||||
return fromChannel(channel, StandardCharsets.UTF_8); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given an opened {@link ReadableByteChannel} and the |
||||
* charset of the bytes contained in the channel. |
||||
* |
||||
* Reads the entire contents of the {@code channel} into |
||||
* the result before returning, then closes the {@code channel}. |
||||
*/ |
||||
public static CharStream fromChannel(ReadableByteChannel channel, Charset charset) throws IOException { |
||||
return fromChannel( |
||||
channel, |
||||
DEFAULT_BUFFER_SIZE, |
||||
CodingErrorAction.REPLACE, |
||||
IntStream.UNKNOWN_SOURCE_NAME); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given a {@link Reader}. Closes |
||||
* the reader before returning. |
||||
*/ |
||||
public static CodePointCharStream fromReader(Reader r) throws IOException { |
||||
return fromReader(r, IntStream.UNKNOWN_SOURCE_NAME); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given a {@link Reader} and its |
||||
* source name. Closes the reader before returning. |
||||
*/ |
||||
public static CodePointCharStream fromReader(Reader r, String sourceName) throws IOException { |
||||
try { |
||||
CodePointBuffer.Builder codePointBufferBuilder = CodePointBuffer.builder(DEFAULT_BUFFER_SIZE); |
||||
CharBuffer charBuffer = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); |
||||
while ((r.read(charBuffer)) != -1) { |
||||
charBuffer.flip(); |
||||
codePointBufferBuilder.append(charBuffer); |
||||
charBuffer.compact(); |
||||
} |
||||
return CodePointCharStream.fromBuffer(codePointBufferBuilder.build(), sourceName); |
||||
} |
||||
finally { |
||||
r.close(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given a {@link String}. |
||||
*/ |
||||
public static CodePointCharStream fromString(String s) { |
||||
return fromString(s, IntStream.UNKNOWN_SOURCE_NAME); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given a {@link String} and the {@code sourceName} |
||||
* from which it came. |
||||
*/ |
||||
public static CodePointCharStream fromString(String s, String sourceName) { |
||||
// Initial guess assumes no code points > U+FFFF: one code
|
||||
// point for each code unit in the string
|
||||
CodePointBuffer.Builder codePointBufferBuilder = CodePointBuffer.builder(s.length()); |
||||
// TODO: CharBuffer.wrap(String) rightfully returns a read-only buffer
|
||||
// which doesn't expose its array, so we make a copy.
|
||||
CharBuffer cb = CharBuffer.allocate(s.length()); |
||||
cb.put(s); |
||||
cb.flip(); |
||||
codePointBufferBuilder.append(cb); |
||||
return CodePointCharStream.fromBuffer(codePointBufferBuilder.build(), sourceName); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link CharStream} given an opened {@link ReadableByteChannel} |
||||
* containing UTF-8 bytes. |
||||
* |
||||
* Reads the entire contents of the {@code channel} into |
||||
* the result before returning, then closes the {@code channel}. |
||||
*/ |
||||
public static CodePointCharStream fromChannel( |
||||
ReadableByteChannel channel, |
||||
int bufferSize, |
||||
CodingErrorAction decodingErrorAction, |
||||
String sourceName) |
||||
throws IOException |
||||
{ |
||||
return fromChannel(channel, StandardCharsets.UTF_8, bufferSize, decodingErrorAction, sourceName, -1); |
||||
} |
||||
|
||||
public static CodePointCharStream fromChannel( |
||||
ReadableByteChannel channel, |
||||
Charset charset, |
||||
int bufferSize, |
||||
CodingErrorAction decodingErrorAction, |
||||
String sourceName, |
||||
long inputSize) |
||||
throws IOException |
||||
{ |
||||
try { |
||||
ByteBuffer utf8BytesIn = ByteBuffer.allocate(bufferSize); |
||||
CharBuffer utf16CodeUnitsOut = CharBuffer.allocate(bufferSize); |
||||
if (inputSize == -1) { |
||||
inputSize = bufferSize; |
||||
} else if (inputSize > Integer.MAX_VALUE) { |
||||
// ByteBuffer et al don't support long sizes
|
||||
throw new IOException(String.format("inputSize %d larger than max %d", inputSize, Integer.MAX_VALUE)); |
||||
} |
||||
CodePointBuffer.Builder codePointBufferBuilder = CodePointBuffer.builder((int) inputSize); |
||||
CharsetDecoder decoder = charset |
||||
.newDecoder() |
||||
.onMalformedInput(decodingErrorAction) |
||||
.onUnmappableCharacter(decodingErrorAction); |
||||
|
||||
boolean endOfInput = false; |
||||
while (!endOfInput) { |
||||
int bytesRead = channel.read(utf8BytesIn); |
||||
endOfInput = (bytesRead == -1); |
||||
utf8BytesIn.flip(); |
||||
CoderResult result = decoder.decode( |
||||
utf8BytesIn, |
||||
utf16CodeUnitsOut, |
||||
endOfInput); |
||||
if (result.isError() && decodingErrorAction.equals(CodingErrorAction.REPORT)) { |
||||
result.throwException(); |
||||
} |
||||
utf16CodeUnitsOut.flip(); |
||||
codePointBufferBuilder.append(utf16CodeUnitsOut); |
||||
utf8BytesIn.compact(); |
||||
utf16CodeUnitsOut.compact(); |
||||
} |
||||
// Handle any bytes at the end of the file which need to
|
||||
// be represented as errors or substitution characters.
|
||||
CoderResult flushResult = decoder.flush(utf16CodeUnitsOut); |
||||
if (flushResult.isError() && decodingErrorAction.equals(CodingErrorAction.REPORT)) { |
||||
flushResult.throwException(); |
||||
} |
||||
utf16CodeUnitsOut.flip(); |
||||
codePointBufferBuilder.append(utf16CodeUnitsOut); |
||||
|
||||
CodePointBuffer codePointBuffer = codePointBufferBuilder.build(); |
||||
return CodePointCharStream.fromBuffer(codePointBuffer, sourceName); |
||||
} |
||||
finally { |
||||
channel.close(); |
||||
} |
||||
} |
||||
} |
@ -1,389 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
import java.nio.CharBuffer; |
||||
import java.nio.IntBuffer; |
||||
|
||||
/** |
||||
* Wrapper for {@link ByteBuffer} / {@link CharBuffer} / {@link IntBuffer}. |
||||
* |
||||
* Because Java lacks generics on primitive types, these three types |
||||
* do not share an interface, so we have to write one manually. |
||||
*/ |
||||
public class CodePointBuffer { |
||||
public enum Type { |
||||
BYTE, |
||||
CHAR, |
||||
INT |
||||
} |
||||
private final Type type; |
||||
private final ByteBuffer byteBuffer; |
||||
private final CharBuffer charBuffer; |
||||
private final IntBuffer intBuffer; |
||||
|
||||
private CodePointBuffer(Type type, ByteBuffer byteBuffer, CharBuffer charBuffer, IntBuffer intBuffer) { |
||||
this.type = type; |
||||
this.byteBuffer = byteBuffer; |
||||
this.charBuffer = charBuffer; |
||||
this.intBuffer = intBuffer; |
||||
} |
||||
|
||||
public static CodePointBuffer withBytes(ByteBuffer byteBuffer) { |
||||
return new CodePointBuffer(Type.BYTE, byteBuffer, null, null); |
||||
} |
||||
|
||||
public static CodePointBuffer withChars(CharBuffer charBuffer) { |
||||
return new CodePointBuffer(Type.CHAR, null, charBuffer, null); |
||||
} |
||||
|
||||
public static CodePointBuffer withInts(IntBuffer intBuffer) { |
||||
return new CodePointBuffer(Type.INT, null, null, intBuffer); |
||||
} |
||||
|
||||
public int position() { |
||||
switch (type) { |
||||
case BYTE: |
||||
return byteBuffer.position(); |
||||
case CHAR: |
||||
return charBuffer.position(); |
||||
case INT: |
||||
return intBuffer.position(); |
||||
} |
||||
throw new UnsupportedOperationException("Not reached"); |
||||
} |
||||
|
||||
public void position(int newPosition) { |
||||
switch (type) { |
||||
case BYTE: |
||||
byteBuffer.position(newPosition); |
||||
break; |
||||
case CHAR: |
||||
charBuffer.position(newPosition); |
||||
break; |
||||
case INT: |
||||
intBuffer.position(newPosition); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
public int remaining() { |
||||
switch (type) { |
||||
case BYTE: |
||||
return byteBuffer.remaining(); |
||||
case CHAR: |
||||
return charBuffer.remaining(); |
||||
case INT: |
||||
return intBuffer.remaining(); |
||||
} |
||||
throw new UnsupportedOperationException("Not reached"); |
||||
} |
||||
|
||||
public int get(int offset) { |
||||
switch (type) { |
||||
case BYTE: |
||||
return byteBuffer.get(offset); |
||||
case CHAR: |
||||
return charBuffer.get(offset); |
||||
case INT: |
||||
return intBuffer.get(offset); |
||||
} |
||||
throw new UnsupportedOperationException("Not reached"); |
||||
} |
||||
|
||||
Type getType() { |
||||
return type; |
||||
} |
||||
|
||||
int arrayOffset() { |
||||
switch (type) { |
||||
case BYTE: |
||||
return byteBuffer.arrayOffset(); |
||||
case CHAR: |
||||
return charBuffer.arrayOffset(); |
||||
case INT: |
||||
return intBuffer.arrayOffset(); |
||||
} |
||||
throw new UnsupportedOperationException("Not reached"); |
||||
} |
||||
|
||||
byte[] byteArray() { |
||||
assert type == Type.BYTE; |
||||
return byteBuffer.array(); |
||||
} |
||||
|
||||
char[] charArray() { |
||||
assert type == Type.CHAR; |
||||
return charBuffer.array(); |
||||
} |
||||
|
||||
int[] intArray() { |
||||
assert type == Type.INT; |
||||
return intBuffer.array(); |
||||
} |
||||
|
||||
public static Builder builder(int initialBufferSize) { |
||||
return new Builder(initialBufferSize); |
||||
} |
||||
|
||||
public static class Builder { |
||||
private Type type; |
||||
private ByteBuffer byteBuffer; |
||||
private CharBuffer charBuffer; |
||||
private IntBuffer intBuffer; |
||||
private int prevHighSurrogate; |
||||
|
||||
private Builder(int initialBufferSize) { |
||||
type = Type.BYTE; |
||||
byteBuffer = ByteBuffer.allocate(initialBufferSize); |
||||
charBuffer = null; |
||||
intBuffer = null; |
||||
prevHighSurrogate = -1; |
||||
} |
||||
|
||||
Type getType() { |
||||
return type; |
||||
} |
||||
|
||||
ByteBuffer getByteBuffer() { |
||||
return byteBuffer; |
||||
} |
||||
|
||||
CharBuffer getCharBuffer() { |
||||
return charBuffer; |
||||
} |
||||
|
||||
IntBuffer getIntBuffer() { |
||||
return intBuffer; |
||||
} |
||||
|
||||
public CodePointBuffer build() { |
||||
switch (type) { |
||||
case BYTE: |
||||
byteBuffer.flip(); |
||||
break; |
||||
case CHAR: |
||||
charBuffer.flip(); |
||||
break; |
||||
case INT: |
||||
intBuffer.flip(); |
||||
break; |
||||
} |
||||
return new CodePointBuffer(type, byteBuffer, charBuffer, intBuffer); |
||||
} |
||||
|
||||
private static int roundUpToNextPowerOfTwo(int i) { |
||||
int nextPowerOfTwo = 32 - Integer.numberOfLeadingZeros(i - 1); |
||||
return (int) Math.pow(2, nextPowerOfTwo); |
||||
} |
||||
|
||||
public void ensureRemaining(int remainingNeeded) { |
||||
switch (type) { |
||||
case BYTE: |
||||
if (byteBuffer.remaining() < remainingNeeded) { |
||||
int newCapacity = roundUpToNextPowerOfTwo(byteBuffer.capacity() + remainingNeeded); |
||||
ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity); |
||||
byteBuffer.flip(); |
||||
newBuffer.put(byteBuffer); |
||||
byteBuffer = newBuffer; |
||||
} |
||||
break; |
||||
case CHAR: |
||||
if (charBuffer.remaining() < remainingNeeded) { |
||||
int newCapacity = roundUpToNextPowerOfTwo(charBuffer.capacity() + remainingNeeded); |
||||
CharBuffer newBuffer = CharBuffer.allocate(newCapacity); |
||||
charBuffer.flip(); |
||||
newBuffer.put(charBuffer); |
||||
charBuffer = newBuffer; |
||||
} |
||||
break; |
||||
case INT: |
||||
if (intBuffer.remaining() < remainingNeeded) { |
||||
int newCapacity = roundUpToNextPowerOfTwo(intBuffer.capacity() + remainingNeeded); |
||||
IntBuffer newBuffer = IntBuffer.allocate(newCapacity); |
||||
intBuffer.flip(); |
||||
newBuffer.put(intBuffer); |
||||
intBuffer = newBuffer; |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
public void append(CharBuffer utf16In) { |
||||
ensureRemaining(utf16In.remaining()); |
||||
if (utf16In.hasArray()) { |
||||
appendArray(utf16In); |
||||
} else { |
||||
// TODO
|
||||
throw new UnsupportedOperationException("TODO"); |
||||
} |
||||
} |
||||
|
||||
private void appendArray(CharBuffer utf16In) { |
||||
assert utf16In.hasArray(); |
||||
|
||||
switch (type) { |
||||
case BYTE: |
||||
appendArrayByte(utf16In); |
||||
break; |
||||
case CHAR: |
||||
appendArrayChar(utf16In); |
||||
break; |
||||
case INT: |
||||
appendArrayInt(utf16In); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
private void appendArrayByte(CharBuffer utf16In) { |
||||
assert prevHighSurrogate == -1; |
||||
|
||||
char[] in = utf16In.array(); |
||||
int inOffset = utf16In.arrayOffset() + utf16In.position(); |
||||
int inLimit = utf16In.arrayOffset() + utf16In.limit(); |
||||
|
||||
byte[] outByte = byteBuffer.array(); |
||||
int outOffset = byteBuffer.arrayOffset() + byteBuffer.position(); |
||||
|
||||
while (inOffset < inLimit) { |
||||
char c = in[inOffset]; |
||||
if (c <= 0xFF) { |
||||
outByte[outOffset] = (byte)(c & 0xFF); |
||||
} else { |
||||
utf16In.position(inOffset - utf16In.arrayOffset()); |
||||
byteBuffer.position(outOffset - byteBuffer.arrayOffset()); |
||||
if (!Character.isHighSurrogate(c)) { |
||||
byteToCharBuffer(utf16In.remaining()); |
||||
appendArrayChar(utf16In); |
||||
return; |
||||
} else { |
||||
byteToIntBuffer(utf16In.remaining()); |
||||
appendArrayInt(utf16In); |
||||
return; |
||||
} |
||||
} |
||||
inOffset++; |
||||
outOffset++; |
||||
} |
||||
|
||||
utf16In.position(inOffset - utf16In.arrayOffset()); |
||||
byteBuffer.position(outOffset - byteBuffer.arrayOffset()); |
||||
} |
||||
|
||||
private void appendArrayChar(CharBuffer utf16In) { |
||||
assert prevHighSurrogate == -1; |
||||
|
||||
char[] in = utf16In.array(); |
||||
int inOffset = utf16In.arrayOffset() + utf16In.position(); |
||||
int inLimit = utf16In.arrayOffset() + utf16In.limit(); |
||||
|
||||
char[] outChar = charBuffer.array(); |
||||
int outOffset = charBuffer.arrayOffset() + charBuffer.position(); |
||||
|
||||
while (inOffset < inLimit) { |
||||
char c = in[inOffset]; |
||||
if (!Character.isHighSurrogate(c)) { |
||||
outChar[outOffset] = c; |
||||
} else { |
||||
utf16In.position(inOffset - utf16In.arrayOffset()); |
||||
charBuffer.position(outOffset - charBuffer.arrayOffset()); |
||||
charToIntBuffer(utf16In.remaining()); |
||||
appendArrayInt(utf16In); |
||||
return; |
||||
} |
||||
inOffset++; |
||||
outOffset++; |
||||
} |
||||
|
||||
utf16In.position(inOffset - utf16In.arrayOffset()); |
||||
charBuffer.position(outOffset - charBuffer.arrayOffset()); |
||||
} |
||||
|
||||
private void appendArrayInt(CharBuffer utf16In) { |
||||
char[] in = utf16In.array(); |
||||
int inOffset = utf16In.arrayOffset() + utf16In.position(); |
||||
int inLimit = utf16In.arrayOffset() + utf16In.limit(); |
||||
|
||||
int[] outInt = intBuffer.array(); |
||||
int outOffset = intBuffer.arrayOffset() + intBuffer.position(); |
||||
|
||||
while (inOffset < inLimit) { |
||||
char c = in[inOffset]; |
||||
inOffset++; |
||||
if (prevHighSurrogate != -1) { |
||||
if (Character.isLowSurrogate(c)) { |
||||
outInt[outOffset] = Character.toCodePoint((char) prevHighSurrogate, c); |
||||
outOffset++; |
||||
prevHighSurrogate = -1; |
||||
} else { |
||||
// Dangling high surrogate
|
||||
outInt[outOffset] = prevHighSurrogate; |
||||
outOffset++; |
||||
if (Character.isHighSurrogate(c)) { |
||||
prevHighSurrogate = c & 0xFFFF; |
||||
} else { |
||||
outInt[outOffset] = c & 0xFFFF; |
||||
outOffset++; |
||||
prevHighSurrogate = -1; |
||||
} |
||||
} |
||||
} else if (Character.isHighSurrogate(c)) { |
||||
prevHighSurrogate = c & 0xFFFF; |
||||
} else { |
||||
outInt[outOffset] = c & 0xFFFF; |
||||
outOffset++; |
||||
} |
||||
} |
||||
|
||||
if (prevHighSurrogate != -1) { |
||||
// Dangling high surrogate
|
||||
outInt[outOffset] = prevHighSurrogate & 0xFFFF; |
||||
outOffset++; |
||||
} |
||||
|
||||
utf16In.position(inOffset - utf16In.arrayOffset()); |
||||
intBuffer.position(outOffset - intBuffer.arrayOffset()); |
||||
} |
||||
|
||||
private void byteToCharBuffer(int toAppend) { |
||||
byteBuffer.flip(); |
||||
// CharBuffers hold twice as much per unit as ByteBuffers, so start with half the capacity.
|
||||
CharBuffer newBuffer = CharBuffer.allocate(Math.max(byteBuffer.remaining() + toAppend, byteBuffer.capacity() / 2)); |
||||
while (byteBuffer.hasRemaining()) { |
||||
newBuffer.put((char) (byteBuffer.get() & 0xFF)); |
||||
} |
||||
type = Type.CHAR; |
||||
byteBuffer = null; |
||||
charBuffer = newBuffer; |
||||
} |
||||
|
||||
private void byteToIntBuffer(int toAppend) { |
||||
byteBuffer.flip(); |
||||
// IntBuffers hold four times as much per unit as ByteBuffers, so start with one quarter the capacity.
|
||||
IntBuffer newBuffer = IntBuffer.allocate(Math.max(byteBuffer.remaining() + toAppend, byteBuffer.capacity() / 4)); |
||||
while (byteBuffer.hasRemaining()) { |
||||
newBuffer.put(byteBuffer.get() & 0xFF); |
||||
} |
||||
type = Type.INT; |
||||
byteBuffer = null; |
||||
intBuffer = newBuffer; |
||||
} |
||||
|
||||
private void charToIntBuffer(int toAppend) { |
||||
charBuffer.flip(); |
||||
// IntBuffers hold two times as much per unit as ByteBuffers, so start with one half the capacity.
|
||||
IntBuffer newBuffer = IntBuffer.allocate(Math.max(charBuffer.remaining() + toAppend, charBuffer.capacity() / 2)); |
||||
while (charBuffer.hasRemaining()) { |
||||
newBuffer.put(charBuffer.get() & 0xFFFF); |
||||
} |
||||
type = Type.INT; |
||||
charBuffer = null; |
||||
intBuffer = newBuffer; |
||||
} |
||||
} |
||||
} |
@ -1,297 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
|
||||
import java.nio.charset.StandardCharsets; |
||||
|
||||
/** |
||||
* Alternative to {@link ANTLRInputStream} which treats the input |
||||
* as a series of Unicode code points, instead of a series of UTF-16 |
||||
* code units. |
||||
* |
||||
* Use this if you need to parse input which potentially contains |
||||
* Unicode values > U+FFFF. |
||||
*/ |
||||
public abstract class CodePointCharStream implements CharStream { |
||||
protected final int size; |
||||
protected final String name; |
||||
|
||||
// To avoid lots of virtual method calls, we directly access
|
||||
// the state of the underlying code points in the
|
||||
// CodePointBuffer.
|
||||
protected int position; |
||||
|
||||
// Use the factory method {@link #fromBuffer(CodePointBuffer)} to
|
||||
// construct instances of this type.
|
||||
private CodePointCharStream(int position, int remaining, String name) { |
||||
// TODO
|
||||
assert position == 0; |
||||
this.size = remaining; |
||||
this.name = name; |
||||
this.position = 0; |
||||
} |
||||
|
||||
// Visible for testing.
|
||||
abstract Object getInternalStorage(); |
||||
|
||||
/** |
||||
* Constructs a {@link CodePointCharStream} which provides access |
||||
* to the Unicode code points stored in {@code codePointBuffer}. |
||||
*/ |
||||
public static CodePointCharStream fromBuffer(CodePointBuffer codePointBuffer) { |
||||
return fromBuffer(codePointBuffer, UNKNOWN_SOURCE_NAME); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a named {@link CodePointCharStream} which provides access |
||||
* to the Unicode code points stored in {@code codePointBuffer}. |
||||
*/ |
||||
public static CodePointCharStream fromBuffer(CodePointBuffer codePointBuffer, String name) { |
||||
// Java lacks generics on primitive types.
|
||||
//
|
||||
// To avoid lots of calls to virtual methods in the
|
||||
// very hot codepath of LA() below, we construct one
|
||||
// of three concrete subclasses.
|
||||
//
|
||||
// The concrete subclasses directly access the code
|
||||
// points stored in the underlying array (byte[],
|
||||
// char[], or int[]), so we can avoid lots of virtual
|
||||
// method calls to ByteBuffer.get(offset).
|
||||
switch (codePointBuffer.getType()) { |
||||
case BYTE: |
||||
return new CodePoint8BitCharStream( |
||||
codePointBuffer.position(), |
||||
codePointBuffer.remaining(), |
||||
name, |
||||
codePointBuffer.byteArray(), |
||||
codePointBuffer.arrayOffset()); |
||||
case CHAR: |
||||
return new CodePoint16BitCharStream( |
||||
codePointBuffer.position(), |
||||
codePointBuffer.remaining(), |
||||
name, |
||||
codePointBuffer.charArray(), |
||||
codePointBuffer.arrayOffset()); |
||||
case INT: |
||||
return new CodePoint32BitCharStream( |
||||
codePointBuffer.position(), |
||||
codePointBuffer.remaining(), |
||||
name, |
||||
codePointBuffer.intArray(), |
||||
codePointBuffer.arrayOffset()); |
||||
} |
||||
throw new UnsupportedOperationException("Not reached"); |
||||
} |
||||
|
||||
@Override |
||||
public final void consume() { |
||||
if (size - position == 0) { |
||||
assert LA(1) == IntStream.EOF; |
||||
throw new IllegalStateException("cannot consume EOF"); |
||||
} |
||||
position = position + 1; |
||||
} |
||||
|
||||
@Override |
||||
public final int index() { |
||||
return position; |
||||
} |
||||
|
||||
@Override |
||||
public final int size() { |
||||
return size; |
||||
} |
||||
|
||||
/** mark/release do nothing; we have entire buffer */ |
||||
@Override |
||||
public final int mark() { |
||||
return -1; |
||||
} |
||||
|
||||
@Override |
||||
public final void release(int marker) { |
||||
} |
||||
|
||||
@Override |
||||
public final void seek(int index) { |
||||
position = index; |
||||
} |
||||
|
||||
@Override |
||||
public final String getSourceName() { |
||||
if (name == null || name.isEmpty()) { |
||||
return UNKNOWN_SOURCE_NAME; |
||||
} |
||||
|
||||
return name; |
||||
} |
||||
|
||||
@Override |
||||
public final String toString() { |
||||
return getText(Interval.of(0, size - 1)); |
||||
} |
||||
|
||||
// 8-bit storage for code points <= U+00FF.
|
||||
private static final class CodePoint8BitCharStream extends CodePointCharStream { |
||||
private final byte[] byteArray; |
||||
|
||||
private CodePoint8BitCharStream(int position, int remaining, String name, byte[] byteArray, int arrayOffset) { |
||||
super(position, remaining, name); |
||||
// TODO
|
||||
assert arrayOffset == 0; |
||||
this.byteArray = byteArray; |
||||
} |
||||
|
||||
/** Return the UTF-16 encoded string for the given interval */ |
||||
@Override |
||||
public String getText(Interval interval) { |
||||
int startIdx = Math.min(interval.a, size); |
||||
int len = Math.min(interval.b - interval.a + 1, size - startIdx); |
||||
|
||||
// We know the maximum code point in byteArray is U+00FF,
|
||||
// so we can treat this as if it were ISO-8859-1, aka Latin-1,
|
||||
// which shares the same code points up to 0xFF.
|
||||
return new String(byteArray, startIdx, len, StandardCharsets.ISO_8859_1); |
||||
} |
||||
|
||||
@Override |
||||
public int LA(int i) { |
||||
int offset; |
||||
switch (Integer.signum(i)) { |
||||
case -1: |
||||
offset = position + i; |
||||
if (offset < 0) { |
||||
return IntStream.EOF; |
||||
} |
||||
return byteArray[offset] & 0xFF; |
||||
case 0: |
||||
// Undefined
|
||||
return 0; |
||||
case 1: |
||||
offset = position + i - 1; |
||||
if (offset >= size) { |
||||
return IntStream.EOF; |
||||
} |
||||
return byteArray[offset] & 0xFF; |
||||
} |
||||
throw new UnsupportedOperationException("Not reached"); |
||||
} |
||||
|
||||
@Override |
||||
Object getInternalStorage() { |
||||
return byteArray; |
||||
} |
||||
} |
||||
|
||||
// 16-bit internal storage for code points between U+0100 and U+FFFF.
|
||||
private static final class CodePoint16BitCharStream extends CodePointCharStream { |
||||
private final char[] charArray; |
||||
|
||||
private CodePoint16BitCharStream(int position, int remaining, String name, char[] charArray, int arrayOffset) { |
||||
super(position, remaining, name); |
||||
this.charArray = charArray; |
||||
// TODO
|
||||
assert arrayOffset == 0; |
||||
} |
||||
|
||||
/** Return the UTF-16 encoded string for the given interval */ |
||||
@Override |
||||
public String getText(Interval interval) { |
||||
int startIdx = Math.min(interval.a, size); |
||||
int len = Math.min(interval.b - interval.a + 1, size - startIdx); |
||||
|
||||
// We know there are no surrogates in this
|
||||
// array, since otherwise we would be given a
|
||||
// 32-bit int[] array.
|
||||
//
|
||||
// So, it's safe to treat this as if it were
|
||||
// UTF-16.
|
||||
return new String(charArray, startIdx, len); |
||||
} |
||||
|
||||
@Override |
||||
public int LA(int i) { |
||||
int offset; |
||||
switch (Integer.signum(i)) { |
||||
case -1: |
||||
offset = position + i; |
||||
if (offset < 0) { |
||||
return IntStream.EOF; |
||||
} |
||||
return charArray[offset] & 0xFFFF; |
||||
case 0: |
||||
// Undefined
|
||||
return 0; |
||||
case 1: |
||||
offset = position + i - 1; |
||||
if (offset >= size) { |
||||
return IntStream.EOF; |
||||
} |
||||
return charArray[offset] & 0xFFFF; |
||||
} |
||||
throw new UnsupportedOperationException("Not reached"); |
||||
} |
||||
|
||||
@Override |
||||
Object getInternalStorage() { |
||||
return charArray; |
||||
} |
||||
} |
||||
|
||||
// 32-bit internal storage for code points between U+10000 and U+10FFFF.
|
||||
private static final class CodePoint32BitCharStream extends CodePointCharStream { |
||||
private final int[] intArray; |
||||
|
||||
private CodePoint32BitCharStream(int position, int remaining, String name, int[] intArray, int arrayOffset) { |
||||
super(position, remaining, name); |
||||
this.intArray = intArray; |
||||
// TODO
|
||||
assert arrayOffset == 0; |
||||
} |
||||
|
||||
/** Return the UTF-16 encoded string for the given interval */ |
||||
@Override |
||||
public String getText(Interval interval) { |
||||
int startIdx = Math.min(interval.a, size); |
||||
int len = Math.min(interval.b - interval.a + 1, size - startIdx); |
||||
|
||||
// Note that we pass the int[] code points to the String constructor --
|
||||
// this is supported, and the constructor will convert to UTF-16 internally.
|
||||
return new String(intArray, startIdx, len); |
||||
} |
||||
|
||||
@Override |
||||
public int LA(int i) { |
||||
int offset; |
||||
switch (Integer.signum(i)) { |
||||
case -1: |
||||
offset = position + i; |
||||
if (offset < 0) { |
||||
return IntStream.EOF; |
||||
} |
||||
return intArray[offset]; |
||||
case 0: |
||||
// Undefined
|
||||
return 0; |
||||
case 1: |
||||
offset = position + i - 1; |
||||
if (offset >= size) { |
||||
return IntStream.EOF; |
||||
} |
||||
return intArray[offset]; |
||||
} |
||||
throw new UnsupportedOperationException("Not reached"); |
||||
} |
||||
|
||||
@Override |
||||
Object getInternalStorage() { |
||||
return intArray; |
||||
} |
||||
} |
||||
} |
@ -1,285 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Pair; |
||||
|
||||
import java.io.Serializable; |
||||
|
||||
public class CommonToken implements WritableToken, Serializable { |
||||
/** |
||||
* An empty {@link Pair} which is used as the default value of |
||||
* {@link #source} for tokens that do not have a source. |
||||
*/ |
||||
protected static final Pair<TokenSource, CharStream> EMPTY_SOURCE = |
||||
new Pair<TokenSource, CharStream>(null, null); |
||||
|
||||
/** |
||||
* This is the backing field for {@link #getType} and {@link #setType}. |
||||
*/ |
||||
protected int type; |
||||
|
||||
/** |
||||
* This is the backing field for {@link #getLine} and {@link #setLine}. |
||||
*/ |
||||
protected int line; |
||||
|
||||
/** |
||||
* This is the backing field for {@link #getCharPositionInLine} and |
||||
* {@link #setCharPositionInLine}. |
||||
*/ |
||||
protected int charPositionInLine = -1; // set to invalid position
|
||||
|
||||
/** |
||||
* This is the backing field for {@link #getChannel} and |
||||
* {@link #setChannel}. |
||||
*/ |
||||
protected int channel=DEFAULT_CHANNEL; |
||||
|
||||
/** |
||||
* This is the backing field for {@link #getTokenSource} and |
||||
* {@link #getInputStream}. |
||||
* |
||||
* <p> |
||||
* These properties share a field to reduce the memory footprint of |
||||
* {@link CommonToken}. Tokens created by a {@link CommonTokenFactory} from |
||||
* the same source and input stream share a reference to the same |
||||
* {@link Pair} containing these values.</p> |
||||
*/ |
||||
|
||||
protected Pair<TokenSource, CharStream> source; |
||||
|
||||
/** |
||||
* This is the backing field for {@link #getText} when the token text is |
||||
* explicitly set in the constructor or via {@link #setText}. |
||||
* |
||||
* @see #getText() |
||||
*/ |
||||
protected String text; |
||||
|
||||
/** |
||||
* This is the backing field for {@link #getTokenIndex} and |
||||
* {@link #setTokenIndex}. |
||||
*/ |
||||
protected int index = -1; |
||||
|
||||
/** |
||||
* This is the backing field for {@link #getStartIndex} and |
||||
* {@link #setStartIndex}. |
||||
*/ |
||||
protected int start; |
||||
|
||||
/** |
||||
* This is the backing field for {@link #getStopIndex} and |
||||
* {@link #setStopIndex}. |
||||
*/ |
||||
protected int stop; |
||||
|
||||
/** |
||||
* Constructs a new {@link CommonToken} with the specified token type. |
||||
* |
||||
* @param type The token type. |
||||
*/ |
||||
public CommonToken(int type) { |
||||
this.type = type; |
||||
this.source = EMPTY_SOURCE; |
||||
} |
||||
|
||||
public CommonToken(Pair<TokenSource, CharStream> source, int type, int channel, int start, int stop) { |
||||
this.source = source; |
||||
this.type = type; |
||||
this.channel = channel; |
||||
this.start = start; |
||||
this.stop = stop; |
||||
if (source.a != null) { |
||||
this.line = source.a.getLine(); |
||||
this.charPositionInLine = source.a.getCharPositionInLine(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new {@link CommonToken} with the specified token type and |
||||
* text. |
||||
* |
||||
* @param type The token type. |
||||
* @param text The text of the token. |
||||
*/ |
||||
public CommonToken(int type, String text) { |
||||
this.type = type; |
||||
this.channel = DEFAULT_CHANNEL; |
||||
this.text = text; |
||||
this.source = EMPTY_SOURCE; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new {@link CommonToken} as a copy of another {@link Token}. |
||||
* |
||||
* <p> |
||||
* If {@code oldToken} is also a {@link CommonToken} instance, the newly |
||||
* constructed token will share a reference to the {@link #text} field and |
||||
* the {@link Pair} stored in {@link #source}. Otherwise, {@link #text} will |
||||
* be assigned the result of calling {@link #getText}, and {@link #source} |
||||
* will be constructed from the result of {@link Token#getTokenSource} and |
||||
* {@link Token#getInputStream}.</p> |
||||
* |
||||
* @param oldToken The token to copy. |
||||
*/ |
||||
public CommonToken(Token oldToken) { |
||||
type = oldToken.getType(); |
||||
line = oldToken.getLine(); |
||||
index = oldToken.getTokenIndex(); |
||||
charPositionInLine = oldToken.getCharPositionInLine(); |
||||
channel = oldToken.getChannel(); |
||||
start = oldToken.getStartIndex(); |
||||
stop = oldToken.getStopIndex(); |
||||
|
||||
if (oldToken instanceof CommonToken) { |
||||
text = ((CommonToken)oldToken).text; |
||||
source = ((CommonToken)oldToken).source; |
||||
} |
||||
else { |
||||
text = oldToken.getText(); |
||||
source = new Pair<TokenSource, CharStream>(oldToken.getTokenSource(), oldToken.getInputStream()); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int getType() { |
||||
return type; |
||||
} |
||||
|
||||
@Override |
||||
public void setLine(int line) { |
||||
this.line = line; |
||||
} |
||||
|
||||
@Override |
||||
public String getText() { |
||||
if ( text!=null ) { |
||||
return text; |
||||
} |
||||
|
||||
CharStream input = getInputStream(); |
||||
if ( input==null ) return null; |
||||
int n = input.size(); |
||||
if ( start<n && stop<n) { |
||||
return input.getText(Interval.of(start,stop)); |
||||
} |
||||
else { |
||||
return "<EOF>"; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Explicitly set the text for this token. If {code text} is not |
||||
* {@code null}, then {@link #getText} will return this value rather than |
||||
* extracting the text from the input. |
||||
* |
||||
* @param text The explicit text of the token, or {@code null} if the text |
||||
* should be obtained from the input along with the start and stop indexes |
||||
* of the token. |
||||
*/ |
||||
@Override |
||||
public void setText(String text) { |
||||
this.text = text; |
||||
} |
||||
|
||||
@Override |
||||
public int getLine() { |
||||
return line; |
||||
} |
||||
|
||||
@Override |
||||
public int getCharPositionInLine() { |
||||
return charPositionInLine; |
||||
} |
||||
|
||||
@Override |
||||
public void setCharPositionInLine(int charPositionInLine) { |
||||
this.charPositionInLine = charPositionInLine; |
||||
} |
||||
|
||||
@Override |
||||
public int getChannel() { |
||||
return channel; |
||||
} |
||||
|
||||
@Override |
||||
public void setChannel(int channel) { |
||||
this.channel = channel; |
||||
} |
||||
|
||||
@Override |
||||
public void setType(int type) { |
||||
this.type = type; |
||||
} |
||||
|
||||
@Override |
||||
public int getStartIndex() { |
||||
return start; |
||||
} |
||||
|
||||
public void setStartIndex(int start) { |
||||
this.start = start; |
||||
} |
||||
|
||||
@Override |
||||
public int getStopIndex() { |
||||
return stop; |
||||
} |
||||
|
||||
public void setStopIndex(int stop) { |
||||
this.stop = stop; |
||||
} |
||||
|
||||
@Override |
||||
public int getTokenIndex() { |
||||
return index; |
||||
} |
||||
|
||||
@Override |
||||
public void setTokenIndex(int index) { |
||||
this.index = index; |
||||
} |
||||
|
||||
@Override |
||||
public TokenSource getTokenSource() { |
||||
return source.a; |
||||
} |
||||
|
||||
@Override |
||||
public CharStream getInputStream() { |
||||
return source.b; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return toString(null); |
||||
} |
||||
|
||||
public String toString(Recognizer r) { |
||||
|
||||
String channelStr = ""; |
||||
if ( channel>0 ) { |
||||
channelStr=",channel="+channel; |
||||
} |
||||
String txt = getText(); |
||||
if ( txt!=null ) { |
||||
txt = txt.replace("\n","\\n"); |
||||
txt = txt.replace("\r","\\r"); |
||||
txt = txt.replace("\t","\\t"); |
||||
} |
||||
else { |
||||
txt = "<no text>"; |
||||
} |
||||
String typeString = String.valueOf(type); |
||||
if ( r!=null ) { |
||||
typeString = r.getVocabulary().getDisplayName(type); |
||||
} |
||||
return "[@"+getTokenIndex()+","+start+":"+stop+"='"+txt+"',<"+typeString+">"+channelStr+","+line+":"+getCharPositionInLine()+"]"; |
||||
} |
||||
} |
@ -1,87 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Pair; |
||||
|
||||
/** |
||||
* This default implementation of {@link TokenFactory} creates |
||||
* {@link CommonToken} objects. |
||||
*/ |
||||
public class CommonTokenFactory implements TokenFactory<CommonToken> { |
||||
/** |
||||
* The default {@link CommonTokenFactory} instance. |
||||
* |
||||
* <p> |
||||
* This token factory does not explicitly copy token text when constructing |
||||
* tokens.</p> |
||||
*/ |
||||
public static final TokenFactory<CommonToken> DEFAULT = new CommonTokenFactory(); |
||||
|
||||
/** |
||||
* Indicates whether {@link CommonToken#setText} should be called after |
||||
* constructing tokens to explicitly set the text. This is useful for cases |
||||
* where the input stream might not be able to provide arbitrary substrings |
||||
* of text from the input after the lexer creates a token (e.g. the |
||||
* implementation of {@link CharStream#getText} in |
||||
* {@link UnbufferedCharStream} throws an |
||||
* {@link UnsupportedOperationException}). Explicitly setting the token text |
||||
* allows {@link Token#getText} to be called at any time regardless of the |
||||
* input stream implementation. |
||||
* |
||||
* <p> |
||||
* The default value is {@code false} to avoid the performance and memory |
||||
* overhead of copying text for every token unless explicitly requested.</p> |
||||
*/ |
||||
protected final boolean copyText; |
||||
|
||||
/** |
||||
* Constructs a {@link CommonTokenFactory} with the specified value for |
||||
* {@link #copyText}. |
||||
* |
||||
* <p> |
||||
* When {@code copyText} is {@code false}, the {@link #DEFAULT} instance |
||||
* should be used instead of constructing a new instance.</p> |
||||
* |
||||
* @param copyText The value for {@link #copyText}. |
||||
*/ |
||||
public CommonTokenFactory(boolean copyText) { this.copyText = copyText; } |
||||
|
||||
/** |
||||
* Constructs a {@link CommonTokenFactory} with {@link #copyText} set to |
||||
* {@code false}. |
||||
* |
||||
* <p> |
||||
* The {@link #DEFAULT} instance should be used instead of calling this |
||||
* directly.</p> |
||||
*/ |
||||
public CommonTokenFactory() { this(false); } |
||||
|
||||
@Override |
||||
public CommonToken create(Pair<TokenSource, CharStream> source, int type, String text, |
||||
int channel, int start, int stop, |
||||
int line, int charPositionInLine) |
||||
{ |
||||
CommonToken t = new CommonToken(source, type, channel, start, stop); |
||||
t.setLine(line); |
||||
t.setCharPositionInLine(charPositionInLine); |
||||
if ( text!=null ) { |
||||
t.setText(text); |
||||
} |
||||
else if ( copyText && source.b != null ) { |
||||
t.setText(source.b.getText(Interval.of(start,stop))); |
||||
} |
||||
|
||||
return t; |
||||
} |
||||
|
||||
@Override |
||||
public CommonToken create(int type, String text) { |
||||
return new CommonToken(type, text); |
||||
} |
||||
} |
@ -1,120 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
/** |
||||
* This class extends {@link BufferedTokenStream} with functionality to filter |
||||
* token streams to tokens on a particular channel (tokens where |
||||
* {@link Token#getChannel} returns a particular value). |
||||
* |
||||
* <p> |
||||
* This token stream provides access to all tokens by index or when calling |
||||
* methods like {@link #getText}. The channel filtering is only used for code |
||||
* accessing tokens via the lookahead methods {@link #LA}, {@link #LT}, and |
||||
* {@link #LB}.</p> |
||||
* |
||||
* <p> |
||||
* By default, tokens are placed on the default channel |
||||
* ({@link Token#DEFAULT_CHANNEL}), but may be reassigned by using the |
||||
* {@code ->channel(HIDDEN)} lexer command, or by using an embedded action to |
||||
* call {@link Lexer#setChannel}. |
||||
* </p> |
||||
* |
||||
* <p> |
||||
* Note: lexer rules which use the {@code ->skip} lexer command or call |
||||
* {@link Lexer#skip} do not produce tokens at all, so input text matched by |
||||
* such a rule will not be available as part of the token stream, regardless of |
||||
* channel.</p>we |
||||
*/ |
||||
public class CommonTokenStream extends BufferedTokenStream { |
||||
/** |
||||
* Specifies the channel to use for filtering tokens. |
||||
* |
||||
* <p> |
||||
* The default value is {@link Token#DEFAULT_CHANNEL}, which matches the |
||||
* default channel assigned to tokens created by the lexer.</p> |
||||
*/ |
||||
protected int channel = Token.DEFAULT_CHANNEL; |
||||
|
||||
/** |
||||
* Constructs a new {@link CommonTokenStream} using the specified token |
||||
* source and the default token channel ({@link Token#DEFAULT_CHANNEL}). |
||||
* |
||||
* @param tokenSource The token source. |
||||
*/ |
||||
public CommonTokenStream(TokenSource tokenSource) { |
||||
super(tokenSource); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new {@link CommonTokenStream} using the specified token |
||||
* source and filtering tokens to the specified channel. Only tokens whose |
||||
* {@link Token#getChannel} matches {@code channel} or have the |
||||
* {@link Token#getType} equal to {@link Token#EOF} will be returned by the |
||||
* token stream lookahead methods. |
||||
* |
||||
* @param tokenSource The token source. |
||||
* @param channel The channel to use for filtering tokens. |
||||
*/ |
||||
public CommonTokenStream(TokenSource tokenSource, int channel) { |
||||
this(tokenSource); |
||||
this.channel = channel; |
||||
} |
||||
|
||||
@Override |
||||
protected int adjustSeekIndex(int i) { |
||||
return nextTokenOnChannel(i, channel); |
||||
} |
||||
|
||||
@Override |
||||
protected Token LB(int k) { |
||||
if ( k==0 || (p-k)<0 ) return null; |
||||
|
||||
int i = p; |
||||
int n = 1; |
||||
// find k good tokens looking backwards
|
||||
while ( n<=k && i>0 ) { |
||||
// skip off-channel tokens
|
||||
i = previousTokenOnChannel(i - 1, channel); |
||||
n++; |
||||
} |
||||
if ( i<0 ) return null; |
||||
return tokens.get(i); |
||||
} |
||||
|
||||
@Override |
||||
public Token LT(int k) { |
||||
//System.out.println("enter LT("+k+")");
|
||||
lazyInit(); |
||||
if ( k == 0 ) return null; |
||||
if ( k < 0 ) return LB(-k); |
||||
int i = p; |
||||
int n = 1; // we know tokens[p] is a good one
|
||||
// find k good tokens
|
||||
while ( n<k ) { |
||||
// skip off-channel tokens, but make sure to not look past EOF
|
||||
if (sync(i + 1)) { |
||||
i = nextTokenOnChannel(i + 1, channel); |
||||
} |
||||
n++; |
||||
} |
||||
// if ( i>range ) range = i;
|
||||
return tokens.get(i); |
||||
} |
||||
|
||||
/** Count EOF just once. */ |
||||
public int getNumberOfOnChannelTokens() { |
||||
int n = 0; |
||||
fill(); |
||||
for (int i = 0; i < tokens.size(); i++) { |
||||
Token t = tokens.get(i); |
||||
if ( t.getChannel()==channel ) n++; |
||||
if ( t.getType()==Token.EOF ) break; |
||||
} |
||||
return n; |
||||
} |
||||
} |
@ -1,41 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
/** |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public class ConsoleErrorListener extends BaseErrorListener { |
||||
/** |
||||
* Provides a default instance of {@link ConsoleErrorListener}. |
||||
*/ |
||||
public static final ConsoleErrorListener INSTANCE = new ConsoleErrorListener(); |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* <p> |
||||
* This implementation prints messages to {@link System#err} containing the |
||||
* values of {@code line}, {@code charPositionInLine}, and {@code msg} using |
||||
* the following format.</p> |
||||
* |
||||
* <pre> |
||||
* line <em>line</em>:<em>charPositionInLine</em> <em>msg</em> |
||||
* </pre> |
||||
*/ |
||||
@Override |
||||
public void syntaxError(Recognizer<?, ?> recognizer, |
||||
Object offendingSymbol, |
||||
int line, |
||||
int charPositionInLine, |
||||
String msg, |
||||
RecognitionException e) |
||||
{ |
||||
System.err.println("line " + line + ":" + charPositionInLine + " " + msg); |
||||
} |
||||
|
||||
} |
@ -1,769 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATN; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNState; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.RuleTransition; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntervalSet; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Pair; |
||||
|
||||
/** |
||||
* This is the default implementation of {@link ANTLRErrorStrategy} used for |
||||
* error reporting and recovery in ANTLR parsers. |
||||
*/ |
||||
public class DefaultErrorStrategy implements ANTLRErrorStrategy { |
||||
/** |
||||
* Indicates whether the error strategy is currently "recovering from an |
||||
* error". This is used to suppress reporting multiple error messages while |
||||
* attempting to recover from a detected syntax error. |
||||
* |
||||
* @see #inErrorRecoveryMode |
||||
*/ |
||||
protected boolean errorRecoveryMode = false; |
||||
|
||||
/** The index into the input stream where the last error occurred. |
||||
* This is used to prevent infinite loops where an error is found |
||||
* but no token is consumed during recovery...another error is found, |
||||
* ad nauseum. This is a failsafe mechanism to guarantee that at least |
||||
* one token/tree node is consumed for two errors. |
||||
*/ |
||||
protected int lastErrorIndex = -1; |
||||
|
||||
protected IntervalSet lastErrorStates; |
||||
|
||||
/** |
||||
* This field is used to propagate information about the lookahead following |
||||
* the previous match. Since prediction prefers completing the current rule |
||||
* to error recovery efforts, error reporting may occur later than the |
||||
* original point where it was discoverable. The original context is used to |
||||
* compute the true expected sets as though the reporting occurred as early |
||||
* as possible. |
||||
*/ |
||||
protected ParserRuleContext nextTokensContext; |
||||
|
||||
/** |
||||
* @see #nextTokensContext |
||||
*/ |
||||
protected int nextTokensState; |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* <p>The default implementation simply calls {@link #endErrorCondition} to |
||||
* ensure that the handler is not in error recovery mode.</p> |
||||
*/ |
||||
@Override |
||||
public void reset(Parser recognizer) { |
||||
endErrorCondition(recognizer); |
||||
} |
||||
|
||||
/** |
||||
* This method is called to enter error recovery mode when a recognition |
||||
* exception is reported. |
||||
* |
||||
* @param recognizer the parser instance |
||||
*/ |
||||
protected void beginErrorCondition(Parser recognizer) { |
||||
errorRecoveryMode = true; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public boolean inErrorRecoveryMode(Parser recognizer) { |
||||
return errorRecoveryMode; |
||||
} |
||||
|
||||
/** |
||||
* This method is called to leave error recovery mode after recovering from |
||||
* a recognition exception. |
||||
* |
||||
* @param recognizer |
||||
*/ |
||||
protected void endErrorCondition(Parser recognizer) { |
||||
errorRecoveryMode = false; |
||||
lastErrorStates = null; |
||||
lastErrorIndex = -1; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* <p>The default implementation simply calls {@link #endErrorCondition}.</p> |
||||
*/ |
||||
@Override |
||||
public void reportMatch(Parser recognizer) { |
||||
endErrorCondition(recognizer); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* <p>The default implementation returns immediately if the handler is already |
||||
* in error recovery mode. Otherwise, it calls {@link #beginErrorCondition} |
||||
* and dispatches the reporting task based on the runtime type of {@code e} |
||||
* according to the following table.</p> |
||||
* |
||||
* <ul> |
||||
* <li>{@link NoViableAltException}: Dispatches the call to |
||||
* {@link #reportNoViableAlternative}</li> |
||||
* <li>{@link InputMismatchException}: Dispatches the call to |
||||
* {@link #reportInputMismatch}</li> |
||||
* <li>{@link FailedPredicateException}: Dispatches the call to |
||||
* {@link #reportFailedPredicate}</li> |
||||
* <li>All other types: calls {@link Parser#notifyErrorListeners} to report |
||||
* the exception</li> |
||||
* </ul> |
||||
*/ |
||||
@Override |
||||
public void reportError(Parser recognizer, |
||||
RecognitionException e) |
||||
{ |
||||
// if we've already reported an error and have not matched a token
|
||||
// yet successfully, don't report any errors.
|
||||
if (inErrorRecoveryMode(recognizer)) { |
||||
// System.err.print("[SPURIOUS] ");
|
||||
return; // don't report spurious errors
|
||||
} |
||||
beginErrorCondition(recognizer); |
||||
if ( e instanceof NoViableAltException ) { |
||||
reportNoViableAlternative(recognizer, (NoViableAltException) e); |
||||
} |
||||
else if ( e instanceof InputMismatchException ) { |
||||
reportInputMismatch(recognizer, (InputMismatchException)e); |
||||
} |
||||
else if ( e instanceof FailedPredicateException ) { |
||||
reportFailedPredicate(recognizer, (FailedPredicateException)e); |
||||
} |
||||
else { |
||||
System.err.println("unknown recognition error type: "+e.getClass().getName()); |
||||
recognizer.notifyErrorListeners(e.getOffendingToken(), e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* <p>The default implementation resynchronizes the parser by consuming tokens |
||||
* until we find one in the resynchronization set--loosely the set of tokens |
||||
* that can follow the current rule.</p> |
||||
*/ |
||||
@Override |
||||
public void recover(Parser recognizer, RecognitionException e) { |
||||
// System.out.println("recover in "+recognizer.getRuleInvocationStack()+
|
||||
// " index="+recognizer.getInputStream().index()+
|
||||
// ", lastErrorIndex="+
|
||||
// lastErrorIndex+
|
||||
// ", states="+lastErrorStates);
|
||||
if ( lastErrorIndex==recognizer.getInputStream().index() && |
||||
lastErrorStates != null && |
||||
lastErrorStates.contains(recognizer.getState()) ) { |
||||
// uh oh, another error at same token index and previously-visited
|
||||
// state in ATN; must be a case where LT(1) is in the recovery
|
||||
// token set so nothing got consumed. Consume a single token
|
||||
// at least to prevent an infinite loop; this is a failsafe.
|
||||
// System.err.println("seen error condition before index="+
|
||||
// lastErrorIndex+", states="+lastErrorStates);
|
||||
// System.err.println("FAILSAFE consumes "+recognizer.getTokenNames()[recognizer.getInputStream().LA(1)]);
|
||||
recognizer.consume(); |
||||
} |
||||
lastErrorIndex = recognizer.getInputStream().index(); |
||||
if ( lastErrorStates==null ) lastErrorStates = new IntervalSet(); |
||||
lastErrorStates.add(recognizer.getState()); |
||||
IntervalSet followSet = getErrorRecoverySet(recognizer); |
||||
consumeUntil(recognizer, followSet); |
||||
} |
||||
|
||||
/** |
||||
* The default implementation of {@link ANTLRErrorStrategy#sync} makes sure |
||||
* that the current lookahead symbol is consistent with what were expecting |
||||
* at this point in the ATN. You can call this anytime but ANTLR only |
||||
* generates code to check before subrules/loops and each iteration. |
||||
* |
||||
* <p>Implements Jim Idle's magic sync mechanism in closures and optional |
||||
* subrules. E.g.,</p> |
||||
* |
||||
* <pre> |
||||
* a : sync ( stuff sync )* ; |
||||
* sync : {consume to what can follow sync} ; |
||||
* </pre> |
||||
* |
||||
* At the start of a sub rule upon error, {@link #sync} performs single |
||||
* token deletion, if possible. If it can't do that, it bails on the current |
||||
* rule and uses the default error recovery, which consumes until the |
||||
* resynchronization set of the current rule. |
||||
* |
||||
* <p>If the sub rule is optional ({@code (...)?}, {@code (...)*}, or block |
||||
* with an empty alternative), then the expected set includes what follows |
||||
* the subrule.</p> |
||||
* |
||||
* <p>During loop iteration, it consumes until it sees a token that can start a |
||||
* sub rule or what follows loop. Yes, that is pretty aggressive. We opt to |
||||
* stay in the loop as long as possible.</p> |
||||
* |
||||
* <p><strong>ORIGINS</strong></p> |
||||
* |
||||
* <p>Previous versions of ANTLR did a poor job of their recovery within loops. |
||||
* A single mismatch token or missing token would force the parser to bail |
||||
* out of the entire rules surrounding the loop. So, for rule</p> |
||||
* |
||||
* <pre> |
||||
* classDef : 'class' ID '{' member* '}' |
||||
* </pre> |
||||
* |
||||
* input with an extra token between members would force the parser to |
||||
* consume until it found the next class definition rather than the next |
||||
* member definition of the current class. |
||||
* |
||||
* <p>This functionality cost a little bit of effort because the parser has to |
||||
* compare token set at the start of the loop and at each iteration. If for |
||||
* some reason speed is suffering for you, you can turn off this |
||||
* functionality by simply overriding this method as a blank { }.</p> |
||||
*/ |
||||
@Override |
||||
public void sync(Parser recognizer) throws RecognitionException { |
||||
ATNState s = recognizer.getInterpreter().atn.states.get(recognizer.getState()); |
||||
// System.err.println("sync @ "+s.stateNumber+"="+s.getClass().getSimpleName());
|
||||
// If already recovering, don't try to sync
|
||||
if (inErrorRecoveryMode(recognizer)) { |
||||
return; |
||||
} |
||||
|
||||
TokenStream tokens = recognizer.getInputStream(); |
||||
int la = tokens.LA(1); |
||||
|
||||
// try cheaper subset first; might get lucky. seems to shave a wee bit off
|
||||
IntervalSet nextTokens = recognizer.getATN().nextTokens(s); |
||||
if (nextTokens.contains(la)) { |
||||
// We are sure the token matches
|
||||
nextTokensContext = null; |
||||
nextTokensState = ATNState.INVALID_STATE_NUMBER; |
||||
return; |
||||
} |
||||
|
||||
if (nextTokens.contains(Token.EPSILON)) { |
||||
if (nextTokensContext == null) { |
||||
// It's possible the next token won't match; information tracked
|
||||
// by sync is restricted for performance.
|
||||
nextTokensContext = recognizer.getContext(); |
||||
nextTokensState = recognizer.getState(); |
||||
} |
||||
return; |
||||
} |
||||
|
||||
switch (s.getStateType()) { |
||||
case ATNState.BLOCK_START: |
||||
case ATNState.STAR_BLOCK_START: |
||||
case ATNState.PLUS_BLOCK_START: |
||||
case ATNState.STAR_LOOP_ENTRY: |
||||
// report error and recover if possible
|
||||
if ( singleTokenDeletion(recognizer)!=null ) { |
||||
return; |
||||
} |
||||
|
||||
throw new InputMismatchException(recognizer); |
||||
|
||||
case ATNState.PLUS_LOOP_BACK: |
||||
case ATNState.STAR_LOOP_BACK: |
||||
// System.err.println("at loop back: "+s.getClass().getSimpleName());
|
||||
reportUnwantedToken(recognizer); |
||||
IntervalSet expecting = recognizer.getExpectedTokens(); |
||||
IntervalSet whatFollowsLoopIterationOrRule = |
||||
expecting.or(getErrorRecoverySet(recognizer)); |
||||
consumeUntil(recognizer, whatFollowsLoopIterationOrRule); |
||||
break; |
||||
|
||||
default: |
||||
// do nothing if we can't identify the exact kind of ATN state
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This is called by {@link #reportError} when the exception is a |
||||
* {@link NoViableAltException}. |
||||
* |
||||
* @see #reportError |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @param e the recognition exception |
||||
*/ |
||||
protected void reportNoViableAlternative(Parser recognizer, |
||||
NoViableAltException e) |
||||
{ |
||||
TokenStream tokens = recognizer.getInputStream(); |
||||
String input; |
||||
if ( tokens!=null ) { |
||||
if ( e.getStartToken().getType()==Token.EOF ) input = "<EOF>"; |
||||
else input = tokens.getText(e.getStartToken(), e.getOffendingToken()); |
||||
} |
||||
else { |
||||
input = "<unknown input>"; |
||||
} |
||||
String msg = "no viable alternative at input "+escapeWSAndQuote(input); |
||||
recognizer.notifyErrorListeners(e.getOffendingToken(), msg, e); |
||||
} |
||||
|
||||
/** |
||||
* This is called by {@link #reportError} when the exception is an |
||||
* {@link InputMismatchException}. |
||||
* |
||||
* @see #reportError |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @param e the recognition exception |
||||
*/ |
||||
protected void reportInputMismatch(Parser recognizer, |
||||
InputMismatchException e) |
||||
{ |
||||
String msg = "mismatched input "+getTokenErrorDisplay(e.getOffendingToken())+ |
||||
" expecting "+e.getExpectedTokens().toString(recognizer.getVocabulary()); |
||||
recognizer.notifyErrorListeners(e.getOffendingToken(), msg, e); |
||||
} |
||||
|
||||
/** |
||||
* This is called by {@link #reportError} when the exception is a |
||||
* {@link FailedPredicateException}. |
||||
* |
||||
* @see #reportError |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @param e the recognition exception |
||||
*/ |
||||
protected void reportFailedPredicate(Parser recognizer, |
||||
FailedPredicateException e) |
||||
{ |
||||
String ruleName = recognizer.getRuleNames()[recognizer._ctx.getRuleIndex()]; |
||||
String msg = "rule "+ruleName+" "+e.getMessage(); |
||||
recognizer.notifyErrorListeners(e.getOffendingToken(), msg, e); |
||||
} |
||||
|
||||
/** |
||||
* This method is called to report a syntax error which requires the removal |
||||
* of a token from the input stream. At the time this method is called, the |
||||
* erroneous symbol is current {@code LT(1)} symbol and has not yet been |
||||
* removed from the input stream. When this method returns, |
||||
* {@code recognizer} is in error recovery mode. |
||||
* |
||||
* <p>This method is called when {@link #singleTokenDeletion} identifies |
||||
* single-token deletion as a viable recovery strategy for a mismatched |
||||
* input error.</p> |
||||
* |
||||
* <p>The default implementation simply returns if the handler is already in |
||||
* error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to |
||||
* enter error recovery mode, followed by calling |
||||
* {@link Parser#notifyErrorListeners}.</p> |
||||
* |
||||
* @param recognizer the parser instance |
||||
*/ |
||||
protected void reportUnwantedToken(Parser recognizer) { |
||||
if (inErrorRecoveryMode(recognizer)) { |
||||
return; |
||||
} |
||||
|
||||
beginErrorCondition(recognizer); |
||||
|
||||
Token t = recognizer.getCurrentToken(); |
||||
String tokenName = getTokenErrorDisplay(t); |
||||
IntervalSet expecting = getExpectedTokens(recognizer); |
||||
String msg = "extraneous input "+tokenName+" expecting "+ |
||||
expecting.toString(recognizer.getVocabulary()); |
||||
recognizer.notifyErrorListeners(t, msg, null); |
||||
} |
||||
|
||||
/** |
||||
* This method is called to report a syntax error which requires the |
||||
* insertion of a missing token into the input stream. At the time this |
||||
* method is called, the missing token has not yet been inserted. When this |
||||
* method returns, {@code recognizer} is in error recovery mode. |
||||
* |
||||
* <p>This method is called when {@link #singleTokenInsertion} identifies |
||||
* single-token insertion as a viable recovery strategy for a mismatched |
||||
* input error.</p> |
||||
* |
||||
* <p>The default implementation simply returns if the handler is already in |
||||
* error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to |
||||
* enter error recovery mode, followed by calling |
||||
* {@link Parser#notifyErrorListeners}.</p> |
||||
* |
||||
* @param recognizer the parser instance |
||||
*/ |
||||
protected void reportMissingToken(Parser recognizer) { |
||||
if (inErrorRecoveryMode(recognizer)) { |
||||
return; |
||||
} |
||||
|
||||
beginErrorCondition(recognizer); |
||||
|
||||
Token t = recognizer.getCurrentToken(); |
||||
IntervalSet expecting = getExpectedTokens(recognizer); |
||||
String msg = "missing "+expecting.toString(recognizer.getVocabulary())+ |
||||
" at "+getTokenErrorDisplay(t); |
||||
|
||||
recognizer.notifyErrorListeners(t, msg, null); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* <p>The default implementation attempts to recover from the mismatched input |
||||
* by using single token insertion and deletion as described below. If the |
||||
* recovery attempt fails, this method throws an |
||||
* {@link InputMismatchException}.</p> |
||||
* |
||||
* <p><strong>EXTRA TOKEN</strong> (single token deletion)</p> |
||||
* |
||||
* <p>{@code LA(1)} is not what we are looking for. If {@code LA(2)} has the |
||||
* right token, however, then assume {@code LA(1)} is some extra spurious |
||||
* token and delete it. Then consume and return the next token (which was |
||||
* the {@code LA(2)} token) as the successful result of the match operation.</p> |
||||
* |
||||
* <p>This recovery strategy is implemented by {@link #singleTokenDeletion}.</p> |
||||
* |
||||
* <p><strong>MISSING TOKEN</strong> (single token insertion)</p> |
||||
* |
||||
* <p>If current token (at {@code LA(1)}) is consistent with what could come |
||||
* after the expected {@code LA(1)} token, then assume the token is missing |
||||
* and use the parser's {@link TokenFactory} to create it on the fly. The |
||||
* "insertion" is performed by returning the created token as the successful |
||||
* result of the match operation.</p> |
||||
* |
||||
* <p>This recovery strategy is implemented by {@link #singleTokenInsertion}.</p> |
||||
* |
||||
* <p><strong>EXAMPLE</strong></p> |
||||
* |
||||
* <p>For example, Input {@code i=(3;} is clearly missing the {@code ')'}. When |
||||
* the parser returns from the nested call to {@code expr}, it will have |
||||
* call chain:</p> |
||||
* |
||||
* <pre> |
||||
* stat → expr → atom |
||||
* </pre> |
||||
* |
||||
* and it will be trying to match the {@code ')'} at this point in the |
||||
* derivation: |
||||
* |
||||
* <pre> |
||||
* => ID '=' '(' INT ')' ('+' atom)* ';' |
||||
* ^ |
||||
* </pre> |
||||
* |
||||
* The attempt to match {@code ')'} will fail when it sees {@code ';'} and |
||||
* call {@link #recoverInline}. To recover, it sees that {@code LA(1)==';'} |
||||
* is in the set of tokens that can follow the {@code ')'} token reference |
||||
* in rule {@code atom}. It can assume that you forgot the {@code ')'}. |
||||
*/ |
||||
@Override |
||||
public Token recoverInline(Parser recognizer) |
||||
throws RecognitionException |
||||
{ |
||||
// SINGLE TOKEN DELETION
|
||||
Token matchedSymbol = singleTokenDeletion(recognizer); |
||||
if ( matchedSymbol!=null ) { |
||||
// we have deleted the extra token.
|
||||
// now, move past ttype token as if all were ok
|
||||
recognizer.consume(); |
||||
return matchedSymbol; |
||||
} |
||||
|
||||
// SINGLE TOKEN INSERTION
|
||||
if ( singleTokenInsertion(recognizer) ) { |
||||
return getMissingSymbol(recognizer); |
||||
} |
||||
|
||||
// even that didn't work; must throw the exception
|
||||
InputMismatchException e; |
||||
if (nextTokensContext == null) { |
||||
e = new InputMismatchException(recognizer); |
||||
} else { |
||||
e = new InputMismatchException(recognizer, nextTokensState, nextTokensContext); |
||||
} |
||||
|
||||
throw e; |
||||
} |
||||
|
||||
/** |
||||
* This method implements the single-token insertion inline error recovery |
||||
* strategy. It is called by {@link #recoverInline} if the single-token |
||||
* deletion strategy fails to recover from the mismatched input. If this |
||||
* method returns {@code true}, {@code recognizer} will be in error recovery |
||||
* mode. |
||||
* |
||||
* <p>This method determines whether or not single-token insertion is viable by |
||||
* checking if the {@code LA(1)} input symbol could be successfully matched |
||||
* if it were instead the {@code LA(2)} symbol. If this method returns |
||||
* {@code true}, the caller is responsible for creating and inserting a |
||||
* token with the correct type to produce this behavior.</p> |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @return {@code true} if single-token insertion is a viable recovery |
||||
* strategy for the current mismatched input, otherwise {@code false} |
||||
*/ |
||||
protected boolean singleTokenInsertion(Parser recognizer) { |
||||
int currentSymbolType = recognizer.getInputStream().LA(1); |
||||
// if current token is consistent with what could come after current
|
||||
// ATN state, then we know we're missing a token; error recovery
|
||||
// is free to conjure up and insert the missing token
|
||||
ATNState currentState = recognizer.getInterpreter().atn.states.get(recognizer.getState()); |
||||
ATNState next = currentState.transition(0).target; |
||||
ATN atn = recognizer.getInterpreter().atn; |
||||
IntervalSet expectingAtLL2 = atn.nextTokens(next, recognizer._ctx); |
||||
// System.out.println("LT(2) set="+expectingAtLL2.toString(recognizer.getTokenNames()));
|
||||
if ( expectingAtLL2.contains(currentSymbolType) ) { |
||||
reportMissingToken(recognizer); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* This method implements the single-token deletion inline error recovery |
||||
* strategy. It is called by {@link #recoverInline} to attempt to recover |
||||
* from mismatched input. If this method returns null, the parser and error |
||||
* handler state will not have changed. If this method returns non-null, |
||||
* {@code recognizer} will <em>not</em> be in error recovery mode since the |
||||
* returned token was a successful match. |
||||
* |
||||
* <p>If the single-token deletion is successful, this method calls |
||||
* {@link #reportUnwantedToken} to report the error, followed by |
||||
* {@link Parser#consume} to actually "delete" the extraneous token. Then, |
||||
* before returning {@link #reportMatch} is called to signal a successful |
||||
* match.</p> |
||||
* |
||||
* @param recognizer the parser instance |
||||
* @return the successfully matched {@link Token} instance if single-token |
||||
* deletion successfully recovers from the mismatched input, otherwise |
||||
* {@code null} |
||||
*/ |
||||
protected Token singleTokenDeletion(Parser recognizer) { |
||||
int nextTokenType = recognizer.getInputStream().LA(2); |
||||
IntervalSet expecting = getExpectedTokens(recognizer); |
||||
if ( expecting.contains(nextTokenType) ) { |
||||
reportUnwantedToken(recognizer); |
||||
/* |
||||
System.err.println("recoverFromMismatchedToken deleting "+ |
||||
((TokenStream)recognizer.getInputStream()).LT(1)+ |
||||
" since "+((TokenStream)recognizer.getInputStream()).LT(2)+ |
||||
" is what we want"); |
||||
*/ |
||||
recognizer.consume(); // simply delete extra token
|
||||
// we want to return the token we're actually matching
|
||||
Token matchedSymbol = recognizer.getCurrentToken(); |
||||
reportMatch(recognizer); // we know current token is correct
|
||||
return matchedSymbol; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** Conjure up a missing token during error recovery. |
||||
* |
||||
* The recognizer attempts to recover from single missing |
||||
* symbols. But, actions might refer to that missing symbol. |
||||
* For example, x=ID {f($x);}. The action clearly assumes |
||||
* that there has been an identifier matched previously and that |
||||
* $x points at that token. If that token is missing, but |
||||
* the next token in the stream is what we want we assume that |
||||
* this token is missing and we keep going. Because we |
||||
* have to return some token to replace the missing token, |
||||
* we have to conjure one up. This method gives the user control |
||||
* over the tokens returned for missing tokens. Mostly, |
||||
* you will want to create something special for identifier |
||||
* tokens. For literals such as '{' and ',', the default |
||||
* action in the parser or tree parser works. It simply creates |
||||
* a CommonToken of the appropriate type. The text will be the token. |
||||
* If you change what tokens must be created by the lexer, |
||||
* override this method to create the appropriate tokens. |
||||
*/ |
||||
protected Token getMissingSymbol(Parser recognizer) { |
||||
Token currentSymbol = recognizer.getCurrentToken(); |
||||
IntervalSet expecting = getExpectedTokens(recognizer); |
||||
int expectedTokenType = Token.INVALID_TYPE; |
||||
if ( !expecting.isNil() ) { |
||||
expectedTokenType = expecting.getMinElement(); // get any element
|
||||
} |
||||
String tokenText; |
||||
if ( expectedTokenType== Token.EOF ) tokenText = "<missing EOF>"; |
||||
else tokenText = "<missing "+recognizer.getVocabulary().getDisplayName(expectedTokenType)+">"; |
||||
Token current = currentSymbol; |
||||
Token lookback = recognizer.getInputStream().LT(-1); |
||||
if ( current.getType() == Token.EOF && lookback!=null ) { |
||||
current = lookback; |
||||
} |
||||
return |
||||
recognizer.getTokenFactory().create(new Pair<TokenSource, CharStream>(current.getTokenSource(), current.getTokenSource().getInputStream()), expectedTokenType, tokenText, |
||||
Token.DEFAULT_CHANNEL, |
||||
-1, -1, |
||||
current.getLine(), current.getCharPositionInLine()); |
||||
} |
||||
|
||||
|
||||
protected IntervalSet getExpectedTokens(Parser recognizer) { |
||||
return recognizer.getExpectedTokens(); |
||||
} |
||||
|
||||
/** How should a token be displayed in an error message? The default |
||||
* is to display just the text, but during development you might |
||||
* want to have a lot of information spit out. Override in that case |
||||
* to use t.toString() (which, for CommonToken, dumps everything about |
||||
* the token). This is better than forcing you to override a method in |
||||
* your token objects because you don't have to go modify your lexer |
||||
* so that it creates a new Java type. |
||||
*/ |
||||
protected String getTokenErrorDisplay(Token t) { |
||||
if ( t==null ) return "<no token>"; |
||||
String s = getSymbolText(t); |
||||
if ( s==null ) { |
||||
if ( getSymbolType(t)==Token.EOF ) { |
||||
s = "<EOF>"; |
||||
} |
||||
else { |
||||
s = "<"+getSymbolType(t)+">"; |
||||
} |
||||
} |
||||
return escapeWSAndQuote(s); |
||||
} |
||||
|
||||
protected String getSymbolText(Token symbol) { |
||||
return symbol.getText(); |
||||
} |
||||
|
||||
protected int getSymbolType(Token symbol) { |
||||
return symbol.getType(); |
||||
} |
||||
|
||||
|
||||
protected String escapeWSAndQuote(String s) { |
||||
// if ( s==null ) return s;
|
||||
s = s.replace("\n","\\n"); |
||||
s = s.replace("\r","\\r"); |
||||
s = s.replace("\t","\\t"); |
||||
return "'"+s+"'"; |
||||
} |
||||
|
||||
/* Compute the error recovery set for the current rule. During |
||||
* rule invocation, the parser pushes the set of tokens that can |
||||
* follow that rule reference on the stack; this amounts to |
||||
* computing FIRST of what follows the rule reference in the |
||||
* enclosing rule. See LinearApproximator.FIRST(). |
||||
* This local follow set only includes tokens |
||||
* from within the rule; i.e., the FIRST computation done by |
||||
* ANTLR stops at the end of a rule. |
||||
* |
||||
* EXAMPLE |
||||
* |
||||
* When you find a "no viable alt exception", the input is not |
||||
* consistent with any of the alternatives for rule r. The best |
||||
* thing to do is to consume tokens until you see something that |
||||
* can legally follow a call to r *or* any rule that called r. |
||||
* You don't want the exact set of viable next tokens because the |
||||
* input might just be missing a token--you might consume the |
||||
* rest of the input looking for one of the missing tokens. |
||||
* |
||||
* Consider grammar: |
||||
* |
||||
* a : '[' b ']' |
||||
* | '(' b ')' |
||||
* ; |
||||
* b : c '^' INT ; |
||||
* c : ID |
||||
* | INT |
||||
* ; |
||||
* |
||||
* At each rule invocation, the set of tokens that could follow |
||||
* that rule is pushed on a stack. Here are the various |
||||
* context-sensitive follow sets: |
||||
* |
||||
* FOLLOW(b1_in_a) = FIRST(']') = ']' |
||||
* FOLLOW(b2_in_a) = FIRST(')') = ')' |
||||
* FOLLOW(c_in_b) = FIRST('^') = '^' |
||||
* |
||||
* Upon erroneous input "[]", the call chain is |
||||
* |
||||
* a -> b -> c |
||||
* |
||||
* and, hence, the follow context stack is: |
||||
* |
||||
* depth follow set start of rule execution |
||||
* 0 <EOF> a (from main()) |
||||
* 1 ']' b |
||||
* 2 '^' c |
||||
* |
||||
* Notice that ')' is not included, because b would have to have |
||||
* been called from a different context in rule a for ')' to be |
||||
* included. |
||||
* |
||||
* For error recovery, we cannot consider FOLLOW(c) |
||||
* (context-sensitive or otherwise). We need the combined set of |
||||
* all context-sensitive FOLLOW sets--the set of all tokens that |
||||
* could follow any reference in the call chain. We need to |
||||
* resync to one of those tokens. Note that FOLLOW(c)='^' and if |
||||
* we resync'd to that token, we'd consume until EOF. We need to |
||||
* sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}. |
||||
* In this case, for input "[]", LA(1) is ']' and in the set, so we would |
||||
* not consume anything. After printing an error, rule c would |
||||
* return normally. Rule b would not find the required '^' though. |
||||
* At this point, it gets a mismatched token error and throws an |
||||
* exception (since LA(1) is not in the viable following token |
||||
* set). The rule exception handler tries to recover, but finds |
||||
* the same recovery set and doesn't consume anything. Rule b |
||||
* exits normally returning to rule a. Now it finds the ']' (and |
||||
* with the successful match exits errorRecovery mode). |
||||
* |
||||
* So, you can see that the parser walks up the call chain looking |
||||
* for the token that was a member of the recovery set. |
||||
* |
||||
* Errors are not generated in errorRecovery mode. |
||||
* |
||||
* ANTLR's error recovery mechanism is based upon original ideas: |
||||
* |
||||
* "Algorithms + Data Structures = Programs" by Niklaus Wirth |
||||
* |
||||
* and |
||||
* |
||||
* "A note on error recovery in recursive descent parsers": |
||||
* http://portal.acm.org/citation.cfm?id=947902.947905
|
||||
* |
||||
* Later, Josef Grosch had some good ideas: |
||||
* |
||||
* "Efficient and Comfortable Error Recovery in Recursive Descent |
||||
* Parsers": |
||||
* ftp://www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip
|
||||
* |
||||
* Like Grosch I implement context-sensitive FOLLOW sets that are combined |
||||
* at run-time upon error to avoid overhead during parsing. |
||||
*/ |
||||
protected IntervalSet getErrorRecoverySet(Parser recognizer) { |
||||
ATN atn = recognizer.getInterpreter().atn; |
||||
RuleContext ctx = recognizer._ctx; |
||||
IntervalSet recoverSet = new IntervalSet(); |
||||
while ( ctx!=null && ctx.invokingState>=0 ) { |
||||
// compute what follows who invoked us
|
||||
ATNState invokingState = atn.states.get(ctx.invokingState); |
||||
RuleTransition rt = (RuleTransition)invokingState.transition(0); |
||||
IntervalSet follow = atn.nextTokens(rt.followState); |
||||
recoverSet.addAll(follow); |
||||
ctx = ctx.parent; |
||||
} |
||||
recoverSet.remove(Token.EPSILON); |
||||
// System.out.println("recover set "+recoverSet.toString(recognizer.getTokenNames()));
|
||||
return recoverSet; |
||||
} |
||||
|
||||
/** Consume tokens until one matches the given token set. */ |
||||
protected void consumeUntil(Parser recognizer, IntervalSet set) { |
||||
// System.err.println("consumeUntil("+set.toString(recognizer.getTokenNames())+")");
|
||||
int ttype = recognizer.getInputStream().LA(1); |
||||
while (ttype != Token.EOF && !set.contains(ttype) ) { |
||||
//System.out.println("consume during recover LA(1)="+getTokenNames()[input.LA(1)]);
|
||||
// recognizer.getInputStream().consume();
|
||||
recognizer.consume(); |
||||
ttype = recognizer.getInputStream().LA(1); |
||||
} |
||||
} |
||||
} |
@ -1,153 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNConfig; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNConfigSet; |
||||
import com.fr.third.org.antlr.v4.runtime.dfa.DFA; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
|
||||
import java.util.BitSet; |
||||
|
||||
/** |
||||
* This implementation of {@link ANTLRErrorListener} can be used to identify |
||||
* certain potential correctness and performance problems in grammars. "Reports" |
||||
* are made by calling {@link Parser#notifyErrorListeners} with the appropriate |
||||
* message. |
||||
* |
||||
* <ul> |
||||
* <li><b>Ambiguities</b>: These are cases where more than one path through the |
||||
* grammar can match the input.</li> |
||||
* <li><b>Weak context sensitivity</b>: These are cases where full-context |
||||
* prediction resolved an SLL conflict to a unique alternative which equaled the |
||||
* minimum alternative of the SLL conflict.</li> |
||||
* <li><b>Strong (forced) context sensitivity</b>: These are cases where the |
||||
* full-context prediction resolved an SLL conflict to a unique alternative, |
||||
* <em>and</em> the minimum alternative of the SLL conflict was found to not be |
||||
* a truly viable alternative. Two-stage parsing cannot be used for inputs where |
||||
* this situation occurs.</li> |
||||
* </ul> |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public class DiagnosticErrorListener extends BaseErrorListener { |
||||
/** |
||||
* When {@code true}, only exactly known ambiguities are reported. |
||||
*/ |
||||
protected final boolean exactOnly; |
||||
|
||||
/** |
||||
* Initializes a new instance of {@link DiagnosticErrorListener} which only |
||||
* reports exact ambiguities. |
||||
*/ |
||||
public DiagnosticErrorListener() { |
||||
this(true); |
||||
} |
||||
|
||||
/** |
||||
* Initializes a new instance of {@link DiagnosticErrorListener}, specifying |
||||
* whether all ambiguities or only exact ambiguities are reported. |
||||
* |
||||
* @param exactOnly {@code true} to report only exact ambiguities, otherwise |
||||
* {@code false} to report all ambiguities. |
||||
*/ |
||||
public DiagnosticErrorListener(boolean exactOnly) { |
||||
this.exactOnly = exactOnly; |
||||
} |
||||
|
||||
@Override |
||||
public void reportAmbiguity(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
boolean exact, |
||||
BitSet ambigAlts, |
||||
ATNConfigSet configs) |
||||
{ |
||||
if (exactOnly && !exact) { |
||||
return; |
||||
} |
||||
|
||||
String format = "reportAmbiguity d=%s: ambigAlts=%s, input='%s'"; |
||||
String decision = getDecisionDescription(recognizer, dfa); |
||||
BitSet conflictingAlts = getConflictingAlts(ambigAlts, configs); |
||||
String text = recognizer.getTokenStream().getText(Interval.of(startIndex, stopIndex)); |
||||
String message = String.format(format, decision, conflictingAlts, text); |
||||
recognizer.notifyErrorListeners(message); |
||||
} |
||||
|
||||
@Override |
||||
public void reportAttemptingFullContext(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
BitSet conflictingAlts, |
||||
ATNConfigSet configs) |
||||
{ |
||||
String format = "reportAttemptingFullContext d=%s, input='%s'"; |
||||
String decision = getDecisionDescription(recognizer, dfa); |
||||
String text = recognizer.getTokenStream().getText(Interval.of(startIndex, stopIndex)); |
||||
String message = String.format(format, decision, text); |
||||
recognizer.notifyErrorListeners(message); |
||||
} |
||||
|
||||
@Override |
||||
public void reportContextSensitivity(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
int prediction, |
||||
ATNConfigSet configs) |
||||
{ |
||||
String format = "reportContextSensitivity d=%s, input='%s'"; |
||||
String decision = getDecisionDescription(recognizer, dfa); |
||||
String text = recognizer.getTokenStream().getText(Interval.of(startIndex, stopIndex)); |
||||
String message = String.format(format, decision, text); |
||||
recognizer.notifyErrorListeners(message); |
||||
} |
||||
|
||||
protected String getDecisionDescription(Parser recognizer, DFA dfa) { |
||||
int decision = dfa.decision; |
||||
int ruleIndex = dfa.atnStartState.ruleIndex; |
||||
|
||||
String[] ruleNames = recognizer.getRuleNames(); |
||||
if (ruleIndex < 0 || ruleIndex >= ruleNames.length) { |
||||
return String.valueOf(decision); |
||||
} |
||||
|
||||
String ruleName = ruleNames[ruleIndex]; |
||||
if (ruleName == null || ruleName.isEmpty()) { |
||||
return String.valueOf(decision); |
||||
} |
||||
|
||||
return String.format("%d (%s)", decision, ruleName); |
||||
} |
||||
|
||||
/** |
||||
* Computes the set of conflicting or ambiguous alternatives from a |
||||
* configuration set, if that information was not already provided by the |
||||
* parser. |
||||
* |
||||
* @param reportedAlts The set of conflicting or ambiguous alternatives, as |
||||
* reported by the parser. |
||||
* @param configs The conflicting or ambiguous configuration set. |
||||
* @return Returns {@code reportedAlts} if it is not {@code null}, otherwise |
||||
* returns the set of alternatives represented in {@code configs}. |
||||
*/ |
||||
protected BitSet getConflictingAlts(BitSet reportedAlts, ATNConfigSet configs) { |
||||
if (reportedAlts != null) { |
||||
return reportedAlts; |
||||
} |
||||
|
||||
BitSet result = new BitSet(); |
||||
for (ATNConfig config : configs) { |
||||
result.set(config.alt); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
} |
@ -1,74 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNState; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.AbstractPredicateTransition; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.PredicateTransition; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
/** A semantic predicate failed during validation. Validation of predicates |
||||
* occurs when normally parsing the alternative just like matching a token. |
||||
* Disambiguating predicate evaluation occurs when we test a predicate during |
||||
* prediction. |
||||
*/ |
||||
public class FailedPredicateException extends RecognitionException { |
||||
private final int ruleIndex; |
||||
private final int predicateIndex; |
||||
private final String predicate; |
||||
|
||||
public FailedPredicateException(Parser recognizer) { |
||||
this(recognizer, null); |
||||
} |
||||
|
||||
public FailedPredicateException(Parser recognizer, String predicate) { |
||||
this(recognizer, predicate, null); |
||||
} |
||||
|
||||
public FailedPredicateException(Parser recognizer, |
||||
String predicate, |
||||
String message) |
||||
{ |
||||
super(formatMessage(predicate, message), recognizer, recognizer.getInputStream(), recognizer._ctx); |
||||
ATNState s = recognizer.getInterpreter().atn.states.get(recognizer.getState()); |
||||
|
||||
AbstractPredicateTransition trans = (AbstractPredicateTransition)s.transition(0); |
||||
if (trans instanceof PredicateTransition) { |
||||
this.ruleIndex = ((PredicateTransition)trans).ruleIndex; |
||||
this.predicateIndex = ((PredicateTransition)trans).predIndex; |
||||
} |
||||
else { |
||||
this.ruleIndex = 0; |
||||
this.predicateIndex = 0; |
||||
} |
||||
|
||||
this.predicate = predicate; |
||||
this.setOffendingToken(recognizer.getCurrentToken()); |
||||
} |
||||
|
||||
public int getRuleIndex() { |
||||
return ruleIndex; |
||||
} |
||||
|
||||
public int getPredIndex() { |
||||
return predicateIndex; |
||||
} |
||||
|
||||
|
||||
public String getPredicate() { |
||||
return predicate; |
||||
} |
||||
|
||||
|
||||
private static String formatMessage(String predicate, String message) { |
||||
if (message != null) { |
||||
return message; |
||||
} |
||||
|
||||
return String.format(Locale.getDefault(), "failed predicate: {%s}?", predicate); |
||||
} |
||||
} |
@ -1,22 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
/** This signifies any kind of mismatched input exceptions such as |
||||
* when the current input does not match the expected token. |
||||
*/ |
||||
public class InputMismatchException extends RecognitionException { |
||||
public InputMismatchException(Parser recognizer) { |
||||
super(recognizer, recognizer.getInputStream(), recognizer._ctx); |
||||
this.setOffendingToken(recognizer.getCurrentToken()); |
||||
} |
||||
|
||||
public InputMismatchException(Parser recognizer, int state, ParserRuleContext ctx) { |
||||
super(recognizer, recognizer.getInputStream(), ctx); |
||||
this.setOffendingState(state); |
||||
this.setOffendingToken(recognizer.getCurrentToken()); |
||||
} |
||||
} |
@ -1,216 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
/** |
||||
* A simple stream of symbols whose values are represented as integers. This |
||||
* interface provides <em>marked ranges</em> with support for a minimum level |
||||
* of buffering necessary to implement arbitrary lookahead during prediction. |
||||
* For more information on marked ranges, see {@link #mark}. |
||||
* |
||||
* <p><strong>Initializing Methods:</strong> Some methods in this interface have |
||||
* unspecified behavior if no call to an initializing method has occurred after |
||||
* the stream was constructed. The following is a list of initializing methods:</p> |
||||
* |
||||
* <ul> |
||||
* <li>{@link #LA}</li> |
||||
* <li>{@link #consume}</li> |
||||
* <li>{@link #size}</li> |
||||
* </ul> |
||||
*/ |
||||
public interface IntStream { |
||||
/** |
||||
* The value returned by {@link #LA LA()} when the end of the stream is |
||||
* reached. |
||||
*/ |
||||
public static final int EOF = -1; |
||||
|
||||
/** |
||||
* The value returned by {@link #getSourceName} when the actual name of the |
||||
* underlying source is not known. |
||||
*/ |
||||
public static final String UNKNOWN_SOURCE_NAME = "<unknown>"; |
||||
|
||||
/** |
||||
* Consumes the current symbol in the stream. This method has the following |
||||
* effects: |
||||
* |
||||
* <ul> |
||||
* <li><strong>Forward movement:</strong> The value of {@link #index index()} |
||||
* before calling this method is less than the value of {@code index()} |
||||
* after calling this method.</li> |
||||
* <li><strong>Ordered lookahead:</strong> The value of {@code LA(1)} before |
||||
* calling this method becomes the value of {@code LA(-1)} after calling |
||||
* this method.</li> |
||||
* </ul> |
||||
* |
||||
* Note that calling this method does not guarantee that {@code index()} is |
||||
* incremented by exactly 1, as that would preclude the ability to implement |
||||
* filtering streams (e.g. {@link CommonTokenStream} which distinguishes |
||||
* between "on-channel" and "off-channel" tokens). |
||||
* |
||||
* @throws IllegalStateException if an attempt is made to consume the |
||||
* end of the stream (i.e. if {@code LA(1)==}{@link #EOF EOF} before calling |
||||
* {@code consume}). |
||||
*/ |
||||
void consume(); |
||||
|
||||
/** |
||||
* Gets the value of the symbol at offset {@code i} from the current |
||||
* position. When {@code i==1}, this method returns the value of the current |
||||
* symbol in the stream (which is the next symbol to be consumed). When |
||||
* {@code i==-1}, this method returns the value of the previously read |
||||
* symbol in the stream. It is not valid to call this method with |
||||
* {@code i==0}, but the specific behavior is unspecified because this |
||||
* method is frequently called from performance-critical code. |
||||
* |
||||
* <p>This method is guaranteed to succeed if any of the following are true:</p> |
||||
* |
||||
* <ul> |
||||
* <li>{@code i>0}</li> |
||||
* <li>{@code i==-1} and {@link #index index()} returns a value greater |
||||
* than the value of {@code index()} after the stream was constructed |
||||
* and {@code LA(1)} was called in that order. Specifying the current |
||||
* {@code index()} relative to the index after the stream was created |
||||
* allows for filtering implementations that do not return every symbol |
||||
* from the underlying source. Specifying the call to {@code LA(1)} |
||||
* allows for lazily initialized streams.</li> |
||||
* <li>{@code LA(i)} refers to a symbol consumed within a marked region |
||||
* that has not yet been released.</li> |
||||
* </ul> |
||||
* |
||||
* <p>If {@code i} represents a position at or beyond the end of the stream, |
||||
* this method returns {@link #EOF}.</p> |
||||
* |
||||
* <p>The return value is unspecified if {@code i<0} and fewer than {@code -i} |
||||
* calls to {@link #consume consume()} have occurred from the beginning of |
||||
* the stream before calling this method.</p> |
||||
* |
||||
* @throws UnsupportedOperationException if the stream does not support |
||||
* retrieving the value of the specified symbol |
||||
*/ |
||||
int LA(int i); |
||||
|
||||
/** |
||||
* A mark provides a guarantee that {@link #seek seek()} operations will be |
||||
* valid over a "marked range" extending from the index where {@code mark()} |
||||
* was called to the current {@link #index index()}. This allows the use of |
||||
* streaming input sources by specifying the minimum buffering requirements |
||||
* to support arbitrary lookahead during prediction. |
||||
* |
||||
* <p>The returned mark is an opaque handle (type {@code int}) which is passed |
||||
* to {@link #release release()} when the guarantees provided by the marked |
||||
* range are no longer necessary. When calls to |
||||
* {@code mark()}/{@code release()} are nested, the marks must be released |
||||
* in reverse order of which they were obtained. Since marked regions are |
||||
* used during performance-critical sections of prediction, the specific |
||||
* behavior of invalid usage is unspecified (i.e. a mark is not released, or |
||||
* a mark is released twice, or marks are not released in reverse order from |
||||
* which they were created).</p> |
||||
* |
||||
* <p>The behavior of this method is unspecified if no call to an |
||||
* {@link IntStream initializing method} has occurred after this stream was |
||||
* constructed.</p> |
||||
* |
||||
* <p>This method does not change the current position in the input stream.</p> |
||||
* |
||||
* <p>The following example shows the use of {@link #mark mark()}, |
||||
* {@link #release release(mark)}, {@link #index index()}, and |
||||
* {@link #seek seek(index)} as part of an operation to safely work within a |
||||
* marked region, then restore the stream position to its original value and |
||||
* release the mark.</p> |
||||
* <pre> |
||||
* IntStream stream = ...; |
||||
* int index = -1; |
||||
* int mark = stream.mark(); |
||||
* try { |
||||
* index = stream.index(); |
||||
* // perform work here...
|
||||
* } finally { |
||||
* if (index != -1) { |
||||
* stream.seek(index); |
||||
* } |
||||
* stream.release(mark); |
||||
* } |
||||
* </pre> |
||||
* |
||||
* @return An opaque marker which should be passed to |
||||
* {@link #release release()} when the marked range is no longer required. |
||||
*/ |
||||
int mark(); |
||||
|
||||
/** |
||||
* This method releases a marked range created by a call to |
||||
* {@link #mark mark()}. Calls to {@code release()} must appear in the |
||||
* reverse order of the corresponding calls to {@code mark()}. If a mark is |
||||
* released twice, or if marks are not released in reverse order of the |
||||
* corresponding calls to {@code mark()}, the behavior is unspecified. |
||||
* |
||||
* <p>For more information and an example, see {@link #mark}.</p> |
||||
* |
||||
* @param marker A marker returned by a call to {@code mark()}. |
||||
* @see #mark |
||||
*/ |
||||
void release(int marker); |
||||
|
||||
/** |
||||
* Return the index into the stream of the input symbol referred to by |
||||
* {@code LA(1)}. |
||||
* |
||||
* <p>The behavior of this method is unspecified if no call to an |
||||
* {@link IntStream initializing method} has occurred after this stream was |
||||
* constructed.</p> |
||||
*/ |
||||
int index(); |
||||
|
||||
/** |
||||
* Set the input cursor to the position indicated by {@code index}. If the |
||||
* specified index lies past the end of the stream, the operation behaves as |
||||
* though {@code index} was the index of the EOF symbol. After this method |
||||
* returns without throwing an exception, then at least one of the following |
||||
* will be true. |
||||
* |
||||
* <ul> |
||||
* <li>{@link #index index()} will return the index of the first symbol |
||||
* appearing at or after the specified {@code index}. Specifically, |
||||
* implementations which filter their sources should automatically |
||||
* adjust {@code index} forward the minimum amount required for the |
||||
* operation to target a non-ignored symbol.</li> |
||||
* <li>{@code LA(1)} returns {@link #EOF}</li> |
||||
* </ul> |
||||
* |
||||
* This operation is guaranteed to not throw an exception if {@code index} |
||||
* lies within a marked region. For more information on marked regions, see |
||||
* {@link #mark}. The behavior of this method is unspecified if no call to |
||||
* an {@link IntStream initializing method} has occurred after this stream |
||||
* was constructed. |
||||
* |
||||
* @param index The absolute index to seek to. |
||||
* |
||||
* @throws IllegalArgumentException if {@code index} is less than 0 |
||||
* @throws UnsupportedOperationException if the stream does not support |
||||
* seeking to the specified index |
||||
*/ |
||||
void seek(int index); |
||||
|
||||
/** |
||||
* Returns the total number of symbols in the stream, including a single EOF |
||||
* symbol. |
||||
* |
||||
* @throws UnsupportedOperationException if the size of the stream is |
||||
* unknown. |
||||
*/ |
||||
int size(); |
||||
|
||||
/** |
||||
* Gets the name of the underlying symbol source. This method returns a |
||||
* non-null, non-empty string. If such a name is not known, this method |
||||
* returns {@link #UNKNOWN_SOURCE_NAME}. |
||||
*/ |
||||
|
||||
public String getSourceName(); |
||||
} |
@ -1,46 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
/** |
||||
* This class extends {@link ParserRuleContext} by allowing the value of |
||||
* {@link #getRuleIndex} to be explicitly set for the context. |
||||
* |
||||
* <p> |
||||
* {@link ParserRuleContext} does not include field storage for the rule index |
||||
* since the context classes created by the code generator override the |
||||
* {@link #getRuleIndex} method to return the correct value for that context. |
||||
* Since the parser interpreter does not use the context classes generated for a |
||||
* parser, this class (with slightly more memory overhead per node) is used to |
||||
* provide equivalent functionality.</p> |
||||
*/ |
||||
public class InterpreterRuleContext extends ParserRuleContext { |
||||
/** This is the backing field for {@link #getRuleIndex}. */ |
||||
protected int ruleIndex = -1; |
||||
|
||||
public InterpreterRuleContext() { } |
||||
|
||||
/** |
||||
* Constructs a new {@link InterpreterRuleContext} with the specified |
||||
* parent, invoking state, and rule index. |
||||
* |
||||
* @param parent The parent context. |
||||
* @param invokingStateNumber The invoking state number. |
||||
* @param ruleIndex The rule index for the current context. |
||||
*/ |
||||
public InterpreterRuleContext(ParserRuleContext parent, |
||||
int invokingStateNumber, |
||||
int ruleIndex) |
||||
{ |
||||
super(parent, invokingStateNumber); |
||||
this.ruleIndex = ruleIndex; |
||||
} |
||||
|
||||
@Override |
||||
public int getRuleIndex() { |
||||
return ruleIndex; |
||||
} |
||||
} |
@ -1,410 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.LexerATNSimulator; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntegerStack; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Pair; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.EmptyStackException; |
||||
import java.util.List; |
||||
|
||||
/** A lexer is recognizer that draws input symbols from a character stream. |
||||
* lexer grammars result in a subclass of this object. A Lexer object |
||||
* uses simplified match() and error recovery mechanisms in the interest |
||||
* of speed. |
||||
*/ |
||||
public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator> |
||||
implements TokenSource |
||||
{ |
||||
public static final int DEFAULT_MODE = 0; |
||||
public static final int MORE = -2; |
||||
public static final int SKIP = -3; |
||||
|
||||
public static final int DEFAULT_TOKEN_CHANNEL = Token.DEFAULT_CHANNEL; |
||||
public static final int HIDDEN = Token.HIDDEN_CHANNEL; |
||||
public static final int MIN_CHAR_VALUE = 0x0000; |
||||
public static final int MAX_CHAR_VALUE = 0x10FFFF; |
||||
|
||||
public CharStream _input; |
||||
protected Pair<TokenSource, CharStream> _tokenFactorySourcePair; |
||||
|
||||
/** How to create token objects */ |
||||
protected TokenFactory<?> _factory = CommonTokenFactory.DEFAULT; |
||||
|
||||
/** The goal of all lexer rules/methods is to create a token object. |
||||
* This is an instance variable as multiple rules may collaborate to |
||||
* create a single token. nextToken will return this object after |
||||
* matching lexer rule(s). If you subclass to allow multiple token |
||||
* emissions, then set this to the last token to be matched or |
||||
* something nonnull so that the auto token emit mechanism will not |
||||
* emit another token. |
||||
*/ |
||||
public Token _token; |
||||
|
||||
/** What character index in the stream did the current token start at? |
||||
* Needed, for example, to get the text for current token. Set at |
||||
* the start of nextToken. |
||||
*/ |
||||
public int _tokenStartCharIndex = -1; |
||||
|
||||
/** The line on which the first character of the token resides */ |
||||
public int _tokenStartLine; |
||||
|
||||
/** The character position of first character within the line */ |
||||
public int _tokenStartCharPositionInLine; |
||||
|
||||
/** Once we see EOF on char stream, next token will be EOF. |
||||
* If you have DONE : EOF ; then you see DONE EOF. |
||||
*/ |
||||
public boolean _hitEOF; |
||||
|
||||
/** The channel number for the current token */ |
||||
public int _channel; |
||||
|
||||
/** The token type for the current token */ |
||||
public int _type; |
||||
|
||||
public final IntegerStack _modeStack = new IntegerStack(); |
||||
public int _mode = Lexer.DEFAULT_MODE; |
||||
|
||||
/** You can set the text for the current token to override what is in |
||||
* the input char buffer. Use setText() or can set this instance var. |
||||
*/ |
||||
public String _text; |
||||
|
||||
public Lexer() { } |
||||
|
||||
public Lexer(CharStream input) { |
||||
this._input = input; |
||||
this._tokenFactorySourcePair = new Pair<TokenSource, CharStream>(this, input); |
||||
} |
||||
|
||||
public void reset() { |
||||
// wack Lexer state variables
|
||||
if ( _input !=null ) { |
||||
_input.seek(0); // rewind the input
|
||||
} |
||||
_token = null; |
||||
_type = Token.INVALID_TYPE; |
||||
_channel = Token.DEFAULT_CHANNEL; |
||||
_tokenStartCharIndex = -1; |
||||
_tokenStartCharPositionInLine = -1; |
||||
_tokenStartLine = -1; |
||||
_text = null; |
||||
|
||||
_hitEOF = false; |
||||
_mode = Lexer.DEFAULT_MODE; |
||||
_modeStack.clear(); |
||||
|
||||
getInterpreter().reset(); |
||||
} |
||||
|
||||
/** Return a token from this source; i.e., match a token on the char |
||||
* stream. |
||||
*/ |
||||
@Override |
||||
public Token nextToken() { |
||||
if (_input == null) { |
||||
throw new IllegalStateException("nextToken requires a non-null input stream."); |
||||
} |
||||
|
||||
// Mark start location in char stream so unbuffered streams are
|
||||
// guaranteed at least have text of current token
|
||||
int tokenStartMarker = _input.mark(); |
||||
try{ |
||||
outer: |
||||
while (true) { |
||||
if (_hitEOF) { |
||||
emitEOF(); |
||||
return _token; |
||||
} |
||||
|
||||
_token = null; |
||||
_channel = Token.DEFAULT_CHANNEL; |
||||
_tokenStartCharIndex = _input.index(); |
||||
_tokenStartCharPositionInLine = getInterpreter().getCharPositionInLine(); |
||||
_tokenStartLine = getInterpreter().getLine(); |
||||
_text = null; |
||||
do { |
||||
_type = Token.INVALID_TYPE; |
||||
// System.out.println("nextToken line "+tokenStartLine+" at "+((char)input.LA(1))+
|
||||
// " in mode "+mode+
|
||||
// " at index "+input.index());
|
||||
int ttype; |
||||
try { |
||||
ttype = getInterpreter().match(_input, _mode); |
||||
} |
||||
catch (LexerNoViableAltException e) { |
||||
notifyListeners(e); // report error
|
||||
recover(e); |
||||
ttype = SKIP; |
||||
} |
||||
if ( _input.LA(1)==IntStream.EOF ) { |
||||
_hitEOF = true; |
||||
} |
||||
if ( _type == Token.INVALID_TYPE ) _type = ttype; |
||||
if ( _type ==SKIP ) { |
||||
continue outer; |
||||
} |
||||
} while ( _type ==MORE ); |
||||
if ( _token == null ) emit(); |
||||
return _token; |
||||
} |
||||
} |
||||
finally { |
||||
// make sure we release marker after match or
|
||||
// unbuffered char stream will keep buffering
|
||||
_input.release(tokenStartMarker); |
||||
} |
||||
} |
||||
|
||||
/** Instruct the lexer to skip creating a token for current lexer rule |
||||
* and look for another token. nextToken() knows to keep looking when |
||||
* a lexer rule finishes with token set to SKIP_TOKEN. Recall that |
||||
* if token==null at end of any token rule, it creates one for you |
||||
* and emits it. |
||||
*/ |
||||
public void skip() { |
||||
_type = SKIP; |
||||
} |
||||
|
||||
public void more() { |
||||
_type = MORE; |
||||
} |
||||
|
||||
public void mode(int m) { |
||||
_mode = m; |
||||
} |
||||
|
||||
public void pushMode(int m) { |
||||
if ( LexerATNSimulator.debug ) System.out.println("pushMode "+m); |
||||
_modeStack.push(_mode); |
||||
mode(m); |
||||
} |
||||
|
||||
public int popMode() { |
||||
if ( _modeStack.isEmpty() ) throw new EmptyStackException(); |
||||
if ( LexerATNSimulator.debug ) System.out.println("popMode back to "+ _modeStack.peek()); |
||||
mode( _modeStack.pop() ); |
||||
return _mode; |
||||
} |
||||
|
||||
@Override |
||||
public void setTokenFactory(TokenFactory<?> factory) { |
||||
this._factory = factory; |
||||
} |
||||
|
||||
@Override |
||||
public TokenFactory<? extends Token> getTokenFactory() { |
||||
return _factory; |
||||
} |
||||
|
||||
/** Set the char stream and reset the lexer */ |
||||
@Override |
||||
public void setInputStream(IntStream input) { |
||||
this._input = null; |
||||
this._tokenFactorySourcePair = new Pair<TokenSource, CharStream>(this, _input); |
||||
reset(); |
||||
this._input = (CharStream)input; |
||||
this._tokenFactorySourcePair = new Pair<TokenSource, CharStream>(this, _input); |
||||
} |
||||
|
||||
@Override |
||||
public String getSourceName() { |
||||
return _input.getSourceName(); |
||||
} |
||||
|
||||
@Override |
||||
public CharStream getInputStream() { |
||||
return _input; |
||||
} |
||||
|
||||
/** By default does not support multiple emits per nextToken invocation |
||||
* for efficiency reasons. Subclass and override this method, nextToken, |
||||
* and getToken (to push tokens into a list and pull from that list |
||||
* rather than a single variable as this implementation does). |
||||
*/ |
||||
public void emit(Token token) { |
||||
//System.err.println("emit "+token);
|
||||
this._token = token; |
||||
} |
||||
|
||||
/** The standard method called to automatically emit a token at the |
||||
* outermost lexical rule. The token object should point into the |
||||
* char buffer start..stop. If there is a text override in 'text', |
||||
* use that to set the token's text. Override this method to emit |
||||
* custom Token objects or provide a new factory. |
||||
*/ |
||||
public Token emit() { |
||||
Token t = _factory.create(_tokenFactorySourcePair, _type, _text, _channel, _tokenStartCharIndex, getCharIndex()-1, |
||||
_tokenStartLine, _tokenStartCharPositionInLine); |
||||
emit(t); |
||||
return t; |
||||
} |
||||
|
||||
public Token emitEOF() { |
||||
int cpos = getCharPositionInLine(); |
||||
int line = getLine(); |
||||
Token eof = _factory.create(_tokenFactorySourcePair, Token.EOF, null, Token.DEFAULT_CHANNEL, _input.index(), _input.index()-1, |
||||
line, cpos); |
||||
emit(eof); |
||||
return eof; |
||||
} |
||||
|
||||
@Override |
||||
public int getLine() { |
||||
return getInterpreter().getLine(); |
||||
} |
||||
|
||||
@Override |
||||
public int getCharPositionInLine() { |
||||
return getInterpreter().getCharPositionInLine(); |
||||
} |
||||
|
||||
public void setLine(int line) { |
||||
getInterpreter().setLine(line); |
||||
} |
||||
|
||||
public void setCharPositionInLine(int charPositionInLine) { |
||||
getInterpreter().setCharPositionInLine(charPositionInLine); |
||||
} |
||||
|
||||
/** What is the index of the current character of lookahead? */ |
||||
public int getCharIndex() { |
||||
return _input.index(); |
||||
} |
||||
|
||||
/** Return the text matched so far for the current token or any |
||||
* text override. |
||||
*/ |
||||
public String getText() { |
||||
if ( _text !=null ) { |
||||
return _text; |
||||
} |
||||
return getInterpreter().getText(_input); |
||||
} |
||||
|
||||
/** Set the complete text of this token; it wipes any previous |
||||
* changes to the text. |
||||
*/ |
||||
public void setText(String text) { |
||||
this._text = text; |
||||
} |
||||
|
||||
/** Override if emitting multiple tokens. */ |
||||
public Token getToken() { return _token; } |
||||
|
||||
public void setToken(Token _token) { |
||||
this._token = _token; |
||||
} |
||||
|
||||
public void setType(int ttype) { |
||||
_type = ttype; |
||||
} |
||||
|
||||
public int getType() { |
||||
return _type; |
||||
} |
||||
|
||||
public void setChannel(int channel) { |
||||
_channel = channel; |
||||
} |
||||
|
||||
public int getChannel() { |
||||
return _channel; |
||||
} |
||||
|
||||
public String[] getChannelNames() { return null; } |
||||
|
||||
public String[] getModeNames() { |
||||
return null; |
||||
} |
||||
|
||||
/** Used to print out token names like ID during debugging and |
||||
* error reporting. The generated parsers implement a method |
||||
* that overrides this to point to their String[] tokenNames. |
||||
*/ |
||||
@Override |
||||
@Deprecated |
||||
public String[] getTokenNames() { |
||||
return null; |
||||
} |
||||
|
||||
/** Return a list of all Token objects in input char stream. |
||||
* Forces load of all tokens. Does not include EOF token. |
||||
*/ |
||||
public List<? extends Token> getAllTokens() { |
||||
List<Token> tokens = new ArrayList<Token>(); |
||||
Token t = nextToken(); |
||||
while ( t.getType()!=Token.EOF ) { |
||||
tokens.add(t); |
||||
t = nextToken(); |
||||
} |
||||
return tokens; |
||||
} |
||||
|
||||
public void recover(LexerNoViableAltException e) { |
||||
if (_input.LA(1) != IntStream.EOF) { |
||||
// skip a char and try again
|
||||
getInterpreter().consume(_input); |
||||
} |
||||
} |
||||
|
||||
public void notifyListeners(LexerNoViableAltException e) { |
||||
String text = _input.getText(Interval.of(_tokenStartCharIndex, _input.index())); |
||||
String msg = "token recognition error at: '"+ getErrorDisplay(text) + "'"; |
||||
|
||||
ANTLRErrorListener listener = getErrorListenerDispatch(); |
||||
listener.syntaxError(this, null, _tokenStartLine, _tokenStartCharPositionInLine, msg, e); |
||||
} |
||||
|
||||
public String getErrorDisplay(String s) { |
||||
StringBuilder buf = new StringBuilder(); |
||||
for (char c : s.toCharArray()) { |
||||
buf.append(getErrorDisplay(c)); |
||||
} |
||||
return buf.toString(); |
||||
} |
||||
|
||||
public String getErrorDisplay(int c) { |
||||
String s = String.valueOf((char)c); |
||||
switch ( c ) { |
||||
case Token.EOF : |
||||
s = "<EOF>"; |
||||
break; |
||||
case '\n' : |
||||
s = "\\n"; |
||||
break; |
||||
case '\t' : |
||||
s = "\\t"; |
||||
break; |
||||
case '\r' : |
||||
s = "\\r"; |
||||
break; |
||||
} |
||||
return s; |
||||
} |
||||
|
||||
public String getCharErrorDisplay(int c) { |
||||
String s = getErrorDisplay(c); |
||||
return "'"+s+"'"; |
||||
} |
||||
|
||||
/** Lexers can normally match any char in it's vocabulary after matching |
||||
* a token, so do the easy thing and just kill a character and hope |
||||
* it all works out. You can instead use the rule invocation stack |
||||
* to do sophisticated error recovery if you are in a fragment rule. |
||||
*/ |
||||
public void recover(RecognitionException re) { |
||||
//System.out.println("consuming char "+(char)input.LA(1)+" during recovery");
|
||||
//re.printStackTrace();
|
||||
// TODO: Do we lose character or line position information?
|
||||
_input.consume(); |
||||
} |
||||
} |
@ -1,110 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATN; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNType; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.LexerATNSimulator; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.PredictionContextCache; |
||||
import com.fr.third.org.antlr.v4.runtime.dfa.DFA; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
|
||||
public class LexerInterpreter extends Lexer { |
||||
protected final String grammarFileName; |
||||
protected final ATN atn; |
||||
|
||||
@Deprecated |
||||
protected final String[] tokenNames; |
||||
protected final String[] ruleNames; |
||||
protected final String[] channelNames; |
||||
protected final String[] modeNames; |
||||
|
||||
|
||||
private final Vocabulary vocabulary; |
||||
|
||||
protected final DFA[] _decisionToDFA; |
||||
protected final PredictionContextCache _sharedContextCache = |
||||
new PredictionContextCache(); |
||||
|
||||
@Deprecated |
||||
public LexerInterpreter(String grammarFileName, Collection<String> tokenNames, Collection<String> ruleNames, Collection<String> modeNames, ATN atn, CharStream input) { |
||||
this(grammarFileName, VocabularyImpl.fromTokenNames(tokenNames.toArray(new String[tokenNames.size()])), ruleNames, new ArrayList<String>(), modeNames, atn, input); |
||||
} |
||||
|
||||
@Deprecated |
||||
public LexerInterpreter(String grammarFileName, Vocabulary vocabulary, Collection<String> ruleNames, Collection<String> modeNames, ATN atn, CharStream input) { |
||||
this(grammarFileName, vocabulary, ruleNames, new ArrayList<String>(), modeNames, atn, input); |
||||
} |
||||
|
||||
public LexerInterpreter(String grammarFileName, Vocabulary vocabulary, Collection<String> ruleNames, Collection<String> channelNames, Collection<String> modeNames, ATN atn, CharStream input) { |
||||
super(input); |
||||
|
||||
if (atn.grammarType != ATNType.LEXER) { |
||||
throw new IllegalArgumentException("The ATN must be a lexer ATN."); |
||||
} |
||||
|
||||
this.grammarFileName = grammarFileName; |
||||
this.atn = atn; |
||||
this.tokenNames = new String[atn.maxTokenType]; |
||||
for (int i = 0; i < tokenNames.length; i++) { |
||||
tokenNames[i] = vocabulary.getDisplayName(i); |
||||
} |
||||
|
||||
this.ruleNames = ruleNames.toArray(new String[ruleNames.size()]); |
||||
this.channelNames = channelNames.toArray(new String[channelNames.size()]); |
||||
this.modeNames = modeNames.toArray(new String[modeNames.size()]); |
||||
this.vocabulary = vocabulary; |
||||
|
||||
this._decisionToDFA = new DFA[atn.getNumberOfDecisions()]; |
||||
for (int i = 0; i < _decisionToDFA.length; i++) { |
||||
_decisionToDFA[i] = new DFA(atn.getDecisionState(i), i); |
||||
} |
||||
this._interp = new LexerATNSimulator(this,atn,_decisionToDFA,_sharedContextCache); |
||||
} |
||||
|
||||
@Override |
||||
public ATN getATN() { |
||||
return atn; |
||||
} |
||||
|
||||
@Override |
||||
public String getGrammarFileName() { |
||||
return grammarFileName; |
||||
} |
||||
|
||||
@Override |
||||
@Deprecated |
||||
public String[] getTokenNames() { |
||||
return tokenNames; |
||||
} |
||||
|
||||
@Override |
||||
public String[] getRuleNames() { |
||||
return ruleNames; |
||||
} |
||||
|
||||
@Override |
||||
public String[] getChannelNames() { |
||||
return channelNames; |
||||
} |
||||
|
||||
@Override |
||||
public String[] getModeNames() { |
||||
return modeNames; |
||||
} |
||||
|
||||
@Override |
||||
public Vocabulary getVocabulary() { |
||||
if (vocabulary != null) { |
||||
return vocabulary; |
||||
} |
||||
|
||||
return super.getVocabulary(); |
||||
} |
||||
} |
@ -1,55 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNConfigSet; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Utils; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
public class LexerNoViableAltException extends RecognitionException { |
||||
/** Matching attempted at what input index? */ |
||||
private final int startIndex; |
||||
|
||||
/** Which configurations did we try at input.index() that couldn't match input.LA(1)? */ |
||||
private final ATNConfigSet deadEndConfigs; |
||||
|
||||
public LexerNoViableAltException(Lexer lexer, |
||||
CharStream input, |
||||
int startIndex, |
||||
ATNConfigSet deadEndConfigs) { |
||||
super(lexer, input, null); |
||||
this.startIndex = startIndex; |
||||
this.deadEndConfigs = deadEndConfigs; |
||||
} |
||||
|
||||
public int getStartIndex() { |
||||
return startIndex; |
||||
} |
||||
|
||||
|
||||
public ATNConfigSet getDeadEndConfigs() { |
||||
return deadEndConfigs; |
||||
} |
||||
|
||||
@Override |
||||
public CharStream getInputStream() { |
||||
return (CharStream)super.getInputStream(); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
String symbol = ""; |
||||
if (startIndex >= 0 && startIndex < getInputStream().size()) { |
||||
symbol = getInputStream().getText(Interval.of(startIndex,startIndex)); |
||||
symbol = Utils.escapeWhitespace(symbol, false); |
||||
} |
||||
|
||||
return String.format(Locale.getDefault(), "%s('%s')", LexerNoViableAltException.class.getSimpleName(), symbol); |
||||
} |
||||
} |
@ -1,235 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Pair; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* Provides an implementation of {@link TokenSource} as a wrapper around a list |
||||
* of {@link Token} objects. |
||||
* |
||||
* <p>If the final token in the list is an {@link Token#EOF} token, it will be used |
||||
* as the EOF token for every call to {@link #nextToken} after the end of the |
||||
* list is reached. Otherwise, an EOF token will be created.</p> |
||||
*/ |
||||
public class ListTokenSource implements TokenSource { |
||||
/** |
||||
* The wrapped collection of {@link Token} objects to return. |
||||
*/ |
||||
protected final List<? extends Token> tokens; |
||||
|
||||
/** |
||||
* The name of the input source. If this value is {@code null}, a call to |
||||
* {@link #getSourceName} should return the source name used to create the |
||||
* the next token in {@link #tokens} (or the previous token if the end of |
||||
* the input has been reached). |
||||
*/ |
||||
private final String sourceName; |
||||
|
||||
/** |
||||
* The index into {@link #tokens} of token to return by the next call to |
||||
* {@link #nextToken}. The end of the input is indicated by this value |
||||
* being greater than or equal to the number of items in {@link #tokens}. |
||||
*/ |
||||
protected int i; |
||||
|
||||
/** |
||||
* This field caches the EOF token for the token source. |
||||
*/ |
||||
protected Token eofToken; |
||||
|
||||
/** |
||||
* This is the backing field for {@link #getTokenFactory} and |
||||
* {@link setTokenFactory}. |
||||
*/ |
||||
private TokenFactory<?> _factory = CommonTokenFactory.DEFAULT; |
||||
|
||||
/** |
||||
* Constructs a new {@link ListTokenSource} instance from the specified |
||||
* collection of {@link Token} objects. |
||||
* |
||||
* @param tokens The collection of {@link Token} objects to provide as a |
||||
* {@link TokenSource}. |
||||
* @exception NullPointerException if {@code tokens} is {@code null} |
||||
*/ |
||||
public ListTokenSource(List<? extends Token> tokens) { |
||||
this(tokens, null); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new {@link ListTokenSource} instance from the specified |
||||
* collection of {@link Token} objects and source name. |
||||
* |
||||
* @param tokens The collection of {@link Token} objects to provide as a |
||||
* {@link TokenSource}. |
||||
* @param sourceName The name of the {@link TokenSource}. If this value is |
||||
* {@code null}, {@link #getSourceName} will attempt to infer the name from |
||||
* the next {@link Token} (or the previous token if the end of the input has |
||||
* been reached). |
||||
* |
||||
* @exception NullPointerException if {@code tokens} is {@code null} |
||||
*/ |
||||
public ListTokenSource(List<? extends Token> tokens, String sourceName) { |
||||
if (tokens == null) { |
||||
throw new NullPointerException("tokens cannot be null"); |
||||
} |
||||
|
||||
this.tokens = tokens; |
||||
this.sourceName = sourceName; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public int getCharPositionInLine() { |
||||
if (i < tokens.size()) { |
||||
return tokens.get(i).getCharPositionInLine(); |
||||
} |
||||
else if (eofToken != null) { |
||||
return eofToken.getCharPositionInLine(); |
||||
} |
||||
else if (tokens.size() > 0) { |
||||
// have to calculate the result from the line/column of the previous
|
||||
// token, along with the text of the token.
|
||||
Token lastToken = tokens.get(tokens.size() - 1); |
||||
String tokenText = lastToken.getText(); |
||||
if (tokenText != null) { |
||||
int lastNewLine = tokenText.lastIndexOf('\n'); |
||||
if (lastNewLine >= 0) { |
||||
return tokenText.length() - lastNewLine - 1; |
||||
} |
||||
} |
||||
|
||||
return lastToken.getCharPositionInLine() + lastToken.getStopIndex() - lastToken.getStartIndex() + 1; |
||||
} |
||||
|
||||
// only reach this if tokens is empty, meaning EOF occurs at the first
|
||||
// position in the input
|
||||
return 0; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public Token nextToken() { |
||||
if (i >= tokens.size()) { |
||||
if (eofToken == null) { |
||||
int start = -1; |
||||
if (tokens.size() > 0) { |
||||
int previousStop = tokens.get(tokens.size() - 1).getStopIndex(); |
||||
if (previousStop != -1) { |
||||
start = previousStop + 1; |
||||
} |
||||
} |
||||
|
||||
int stop = Math.max(-1, start - 1); |
||||
eofToken = _factory.create(new Pair<TokenSource, CharStream>(this, getInputStream()), Token.EOF, "EOF", Token.DEFAULT_CHANNEL, start, stop, getLine(), getCharPositionInLine()); |
||||
} |
||||
|
||||
return eofToken; |
||||
} |
||||
|
||||
Token t = tokens.get(i); |
||||
if (i == tokens.size() - 1 && t.getType() == Token.EOF) { |
||||
eofToken = t; |
||||
} |
||||
|
||||
i++; |
||||
return t; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public int getLine() { |
||||
if (i < tokens.size()) { |
||||
return tokens.get(i).getLine(); |
||||
} |
||||
else if (eofToken != null) { |
||||
return eofToken.getLine(); |
||||
} |
||||
else if (tokens.size() > 0) { |
||||
// have to calculate the result from the line/column of the previous
|
||||
// token, along with the text of the token.
|
||||
Token lastToken = tokens.get(tokens.size() - 1); |
||||
int line = lastToken.getLine(); |
||||
|
||||
String tokenText = lastToken.getText(); |
||||
if (tokenText != null) { |
||||
for (int i = 0; i < tokenText.length(); i++) { |
||||
if (tokenText.charAt(i) == '\n') { |
||||
line++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// if no text is available, assume the token did not contain any newline characters.
|
||||
return line; |
||||
} |
||||
|
||||
// only reach this if tokens is empty, meaning EOF occurs at the first
|
||||
// position in the input
|
||||
return 1; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public CharStream getInputStream() { |
||||
if (i < tokens.size()) { |
||||
return tokens.get(i).getInputStream(); |
||||
} |
||||
else if (eofToken != null) { |
||||
return eofToken.getInputStream(); |
||||
} |
||||
else if (tokens.size() > 0) { |
||||
return tokens.get(tokens.size() - 1).getInputStream(); |
||||
} |
||||
|
||||
// no input stream information is available
|
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public String getSourceName() { |
||||
if (sourceName != null) { |
||||
return sourceName; |
||||
} |
||||
|
||||
CharStream inputStream = getInputStream(); |
||||
if (inputStream != null) { |
||||
return inputStream.getSourceName(); |
||||
} |
||||
|
||||
return "List"; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public void setTokenFactory(TokenFactory<?> factory) { |
||||
this._factory = factory; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public TokenFactory<?> getTokenFactory() { |
||||
return _factory; |
||||
} |
||||
} |
@ -1,60 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNConfigSet; |
||||
|
||||
/** Indicates that the parser could not decide which of two or more paths |
||||
* to take based upon the remaining input. It tracks the starting token |
||||
* of the offending input and also knows where the parser was |
||||
* in the various paths when the error. Reported by reportNoViableAlternative() |
||||
*/ |
||||
public class NoViableAltException extends RecognitionException { |
||||
/** Which configurations did we try at input.index() that couldn't match input.LT(1)? */ |
||||
|
||||
private final ATNConfigSet deadEndConfigs; |
||||
|
||||
/** The token object at the start index; the input stream might |
||||
* not be buffering tokens so get a reference to it. (At the |
||||
* time the error occurred, of course the stream needs to keep a |
||||
* buffer all of the tokens but later we might not have access to those.) |
||||
*/ |
||||
|
||||
private final Token startToken; |
||||
|
||||
public NoViableAltException(Parser recognizer) { // LL(1) error
|
||||
this(recognizer, |
||||
recognizer.getInputStream(), |
||||
recognizer.getCurrentToken(), |
||||
recognizer.getCurrentToken(), |
||||
null, |
||||
recognizer._ctx); |
||||
} |
||||
|
||||
public NoViableAltException(Parser recognizer, |
||||
TokenStream input, |
||||
Token startToken, |
||||
Token offendingToken, |
||||
ATNConfigSet deadEndConfigs, |
||||
ParserRuleContext ctx) |
||||
{ |
||||
super(recognizer, input, ctx); |
||||
this.deadEndConfigs = deadEndConfigs; |
||||
this.startToken = startToken; |
||||
this.setOffendingToken(offendingToken); |
||||
} |
||||
|
||||
|
||||
public Token getStartToken() { |
||||
return startToken; |
||||
} |
||||
|
||||
|
||||
public ATNConfigSet getDeadEndConfigs() { |
||||
return deadEndConfigs; |
||||
} |
||||
|
||||
} |
@ -1,950 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATN; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNDeserializationOptions; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNDeserializer; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNSimulator; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNState; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ParseInfo; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ParserATNSimulator; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.PredictionMode; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ProfilingATNSimulator; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.RuleTransition; |
||||
import com.fr.third.org.antlr.v4.runtime.dfa.DFA; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntegerStack; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntervalSet; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.ErrorNode; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.ErrorNodeImpl; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.ParseTreeListener; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.ParseTreeWalker; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.TerminalNode; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.TerminalNodeImpl; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.pattern.ParseTreePattern; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.WeakHashMap; |
||||
|
||||
/** This is all the parsing support code essentially; most of it is error recovery stuff. */ |
||||
public abstract class Parser extends Recognizer<Token, ParserATNSimulator> { |
||||
public class TraceListener implements ParseTreeListener { |
||||
@Override |
||||
public void enterEveryRule(ParserRuleContext ctx) { |
||||
System.out.println("enter " + getRuleNames()[ctx.getRuleIndex()] + |
||||
", LT(1)=" + _input.LT(1).getText()); |
||||
} |
||||
|
||||
@Override |
||||
public void visitTerminal(TerminalNode node) { |
||||
System.out.println("consume "+node.getSymbol()+" rule "+ |
||||
getRuleNames()[_ctx.getRuleIndex()]); |
||||
} |
||||
|
||||
@Override |
||||
public void visitErrorNode(ErrorNode node) { |
||||
} |
||||
|
||||
@Override |
||||
public void exitEveryRule(ParserRuleContext ctx) { |
||||
System.out.println("exit "+getRuleNames()[ctx.getRuleIndex()]+ |
||||
", LT(1)="+_input.LT(1).getText()); |
||||
} |
||||
} |
||||
|
||||
public static class TrimToSizeListener implements ParseTreeListener { |
||||
public static final TrimToSizeListener INSTANCE = new TrimToSizeListener(); |
||||
|
||||
@Override |
||||
public void enterEveryRule(ParserRuleContext ctx) { } |
||||
|
||||
@Override |
||||
public void visitTerminal(TerminalNode node) { } |
||||
|
||||
@Override |
||||
public void visitErrorNode(ErrorNode node) { } |
||||
|
||||
@Override |
||||
public void exitEveryRule(ParserRuleContext ctx) { |
||||
if (ctx.children instanceof ArrayList) { |
||||
((ArrayList<?>)ctx.children).trimToSize(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This field maps from the serialized ATN string to the deserialized {@link ATN} with |
||||
* bypass alternatives. |
||||
* |
||||
* @see ATNDeserializationOptions#isGenerateRuleBypassTransitions() |
||||
*/ |
||||
private static final Map<String, ATN> bypassAltsAtnCache = |
||||
new WeakHashMap<String, ATN>(); |
||||
|
||||
/** |
||||
* The error handling strategy for the parser. The default value is a new |
||||
* instance of {@link DefaultErrorStrategy}. |
||||
* |
||||
* @see #getErrorHandler |
||||
* @see #setErrorHandler |
||||
*/ |
||||
|
||||
protected ANTLRErrorStrategy _errHandler = new DefaultErrorStrategy(); |
||||
|
||||
/** |
||||
* The input stream. |
||||
* |
||||
* @see #getInputStream |
||||
* @see #setInputStream |
||||
*/ |
||||
protected TokenStream _input; |
||||
|
||||
protected final IntegerStack _precedenceStack; |
||||
{ |
||||
_precedenceStack = new IntegerStack(); |
||||
_precedenceStack.push(0); |
||||
} |
||||
|
||||
/** |
||||
* The {@link ParserRuleContext} object for the currently executing rule. |
||||
* This is always non-null during the parsing process. |
||||
*/ |
||||
protected ParserRuleContext _ctx; |
||||
|
||||
/** |
||||
* Specifies whether or not the parser should construct a parse tree during |
||||
* the parsing process. The default value is {@code true}. |
||||
* |
||||
* @see #getBuildParseTree |
||||
* @see #setBuildParseTree |
||||
*/ |
||||
protected boolean _buildParseTrees = true; |
||||
|
||||
|
||||
/** |
||||
* When {@link #setTrace}{@code (true)} is called, a reference to the |
||||
* {@link TraceListener} is stored here so it can be easily removed in a |
||||
* later call to {@link #setTrace}{@code (false)}. The listener itself is |
||||
* implemented as a parser listener so this field is not directly used by |
||||
* other parser methods. |
||||
*/ |
||||
private TraceListener _tracer; |
||||
|
||||
/** |
||||
* The list of {@link ParseTreeListener} listeners registered to receive |
||||
* events during the parse. |
||||
* |
||||
* @see #addParseListener |
||||
*/ |
||||
protected List<ParseTreeListener> _parseListeners; |
||||
|
||||
/** |
||||
* The number of syntax errors reported during parsing. This value is |
||||
* incremented each time {@link #notifyErrorListeners} is called. |
||||
*/ |
||||
protected int _syntaxErrors; |
||||
|
||||
/** Indicates parser has match()ed EOF token. See {@link #exitRule()}. */ |
||||
protected boolean matchedEOF; |
||||
|
||||
public Parser(TokenStream input) { |
||||
setInputStream(input); |
||||
} |
||||
|
||||
/** reset the parser's state */ |
||||
public void reset() { |
||||
if ( getInputStream()!=null ) getInputStream().seek(0); |
||||
_errHandler.reset(this); |
||||
_ctx = null; |
||||
_syntaxErrors = 0; |
||||
matchedEOF = false; |
||||
setTrace(false); |
||||
_precedenceStack.clear(); |
||||
_precedenceStack.push(0); |
||||
ATNSimulator interpreter = getInterpreter(); |
||||
if (interpreter != null) { |
||||
interpreter.reset(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Match current input symbol against {@code ttype}. If the symbol type |
||||
* matches, {@link ANTLRErrorStrategy#reportMatch} and {@link #consume} are |
||||
* called to complete the match process. |
||||
* |
||||
* <p>If the symbol type does not match, |
||||
* {@link ANTLRErrorStrategy#recoverInline} is called on the current error |
||||
* strategy to attempt recovery. If {@link #getBuildParseTree} is |
||||
* {@code true} and the token index of the symbol returned by |
||||
* {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to |
||||
* the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then |
||||
* {@link ParserRuleContext#addErrorNode(ErrorNode)}.</p> |
||||
* |
||||
* @param ttype the token type to match |
||||
* @return the matched symbol |
||||
* @throws RecognitionException if the current input symbol did not match |
||||
* {@code ttype} and the error strategy could not recover from the |
||||
* mismatched symbol |
||||
*/ |
||||
public Token match(int ttype) throws RecognitionException { |
||||
Token t = getCurrentToken(); |
||||
if ( t.getType()==ttype ) { |
||||
if ( ttype==Token.EOF ) { |
||||
matchedEOF = true; |
||||
} |
||||
_errHandler.reportMatch(this); |
||||
consume(); |
||||
} |
||||
else { |
||||
t = _errHandler.recoverInline(this); |
||||
if ( _buildParseTrees && t.getTokenIndex()==-1 ) { |
||||
// we must have conjured up a new token during single token insertion
|
||||
// if it's not the current symbol
|
||||
_ctx.addErrorNode(createErrorNode(_ctx,t)); |
||||
} |
||||
} |
||||
return t; |
||||
} |
||||
|
||||
/** |
||||
* Match current input symbol as a wildcard. If the symbol type matches |
||||
* (i.e. has a value greater than 0), {@link ANTLRErrorStrategy#reportMatch} |
||||
* and {@link #consume} are called to complete the match process. |
||||
* |
||||
* <p>If the symbol type does not match, |
||||
* {@link ANTLRErrorStrategy#recoverInline} is called on the current error |
||||
* strategy to attempt recovery. If {@link #getBuildParseTree} is |
||||
* {@code true} and the token index of the symbol returned by |
||||
* {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to |
||||
* the parse tree by calling {@link Parser#createErrorNode(ParserRuleContext, Token)}. then |
||||
* {@link ParserRuleContext#addErrorNode(ErrorNode)}</p> |
||||
* |
||||
* @return the matched symbol |
||||
* @throws RecognitionException if the current input symbol did not match |
||||
* a wildcard and the error strategy could not recover from the mismatched |
||||
* symbol |
||||
*/ |
||||
public Token matchWildcard() throws RecognitionException { |
||||
Token t = getCurrentToken(); |
||||
if (t.getType() > 0) { |
||||
_errHandler.reportMatch(this); |
||||
consume(); |
||||
} |
||||
else { |
||||
t = _errHandler.recoverInline(this); |
||||
if (_buildParseTrees && t.getTokenIndex() == -1) { |
||||
// we must have conjured up a new token during single token insertion
|
||||
// if it's not the current symbol
|
||||
_ctx.addErrorNode(createErrorNode(_ctx,t)); |
||||
} |
||||
} |
||||
|
||||
return t; |
||||
} |
||||
|
||||
/** |
||||
* Track the {@link ParserRuleContext} objects during the parse and hook |
||||
* them up using the {@link ParserRuleContext#children} list so that it |
||||
* forms a parse tree. The {@link ParserRuleContext} returned from the start |
||||
* rule represents the root of the parse tree. |
||||
* |
||||
* <p>Note that if we are not building parse trees, rule contexts only point |
||||
* upwards. When a rule exits, it returns the context but that gets garbage |
||||
* collected if nobody holds a reference. It points upwards but nobody |
||||
* points at it.</p> |
||||
* |
||||
* <p>When we build parse trees, we are adding all of these contexts to |
||||
* {@link ParserRuleContext#children} list. Contexts are then not candidates |
||||
* for garbage collection.</p> |
||||
*/ |
||||
public void setBuildParseTree(boolean buildParseTrees) { |
||||
this._buildParseTrees = buildParseTrees; |
||||
} |
||||
|
||||
/** |
||||
* Gets whether or not a complete parse tree will be constructed while |
||||
* parsing. This property is {@code true} for a newly constructed parser. |
||||
* |
||||
* @return {@code true} if a complete parse tree will be constructed while |
||||
* parsing, otherwise {@code false} |
||||
*/ |
||||
public boolean getBuildParseTree() { |
||||
return _buildParseTrees; |
||||
} |
||||
|
||||
/** |
||||
* Trim the internal lists of the parse tree during parsing to conserve memory. |
||||
* This property is set to {@code false} by default for a newly constructed parser. |
||||
* |
||||
* @param trimParseTrees {@code true} to trim the capacity of the {@link ParserRuleContext#children} |
||||
* list to its size after a rule is parsed. |
||||
*/ |
||||
public void setTrimParseTree(boolean trimParseTrees) { |
||||
if (trimParseTrees) { |
||||
if (getTrimParseTree()) return; |
||||
addParseListener(TrimToSizeListener.INSTANCE); |
||||
} |
||||
else { |
||||
removeParseListener(TrimToSizeListener.INSTANCE); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @return {@code true} if the {@link ParserRuleContext#children} list is trimmed |
||||
* using the default {@link Parser.TrimToSizeListener} during the parse process. |
||||
*/ |
||||
public boolean getTrimParseTree() { |
||||
return getParseListeners().contains(TrimToSizeListener.INSTANCE); |
||||
} |
||||
|
||||
|
||||
public List<ParseTreeListener> getParseListeners() { |
||||
List<ParseTreeListener> listeners = _parseListeners; |
||||
if (listeners == null) { |
||||
return Collections.emptyList(); |
||||
} |
||||
|
||||
return listeners; |
||||
} |
||||
|
||||
/** |
||||
* Registers {@code listener} to receive events during the parsing process. |
||||
* |
||||
* <p>To support output-preserving grammar transformations (including but not |
||||
* limited to left-recursion removal, automated left-factoring, and |
||||
* optimized code generation), calls to listener methods during the parse |
||||
* may differ substantially from calls made by |
||||
* {@link ParseTreeWalker#DEFAULT} used after the parse is complete. In |
||||
* particular, rule entry and exit events may occur in a different order |
||||
* during the parse than after the parser. In addition, calls to certain |
||||
* rule entry methods may be omitted.</p> |
||||
* |
||||
* <p>With the following specific exceptions, calls to listener events are |
||||
* <em>deterministic</em>, i.e. for identical input the calls to listener |
||||
* methods will be the same.</p> |
||||
* |
||||
* <ul> |
||||
* <li>Alterations to the grammar used to generate code may change the |
||||
* behavior of the listener calls.</li> |
||||
* <li>Alterations to the command line options passed to ANTLR 4 when |
||||
* generating the parser may change the behavior of the listener calls.</li> |
||||
* <li>Changing the version of the ANTLR Tool used to generate the parser |
||||
* may change the behavior of the listener calls.</li> |
||||
* </ul> |
||||
* |
||||
* @param listener the listener to add |
||||
* |
||||
* @throws NullPointerException if {@code} listener is {@code null} |
||||
*/ |
||||
public void addParseListener(ParseTreeListener listener) { |
||||
if (listener == null) { |
||||
throw new NullPointerException("listener"); |
||||
} |
||||
|
||||
if (_parseListeners == null) { |
||||
_parseListeners = new ArrayList<ParseTreeListener>(); |
||||
} |
||||
|
||||
this._parseListeners.add(listener); |
||||
} |
||||
|
||||
/** |
||||
* Remove {@code listener} from the list of parse listeners. |
||||
* |
||||
* <p>If {@code listener} is {@code null} or has not been added as a parse |
||||
* listener, this method does nothing.</p> |
||||
* |
||||
* @see #addParseListener |
||||
* |
||||
* @param listener the listener to remove |
||||
*/ |
||||
public void removeParseListener(ParseTreeListener listener) { |
||||
if (_parseListeners != null) { |
||||
if (_parseListeners.remove(listener)) { |
||||
if (_parseListeners.isEmpty()) { |
||||
_parseListeners = null; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Remove all parse listeners. |
||||
* |
||||
* @see #addParseListener |
||||
*/ |
||||
public void removeParseListeners() { |
||||
_parseListeners = null; |
||||
} |
||||
|
||||
/** |
||||
* Notify any parse listeners of an enter rule event. |
||||
* |
||||
* @see #addParseListener |
||||
*/ |
||||
protected void triggerEnterRuleEvent() { |
||||
for (ParseTreeListener listener : _parseListeners) { |
||||
listener.enterEveryRule(_ctx); |
||||
_ctx.enterRule(listener); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Notify any parse listeners of an exit rule event. |
||||
* |
||||
* @see #addParseListener |
||||
*/ |
||||
protected void triggerExitRuleEvent() { |
||||
// reverse order walk of listeners
|
||||
for (int i = _parseListeners.size()-1; i >= 0; i--) { |
||||
ParseTreeListener listener = _parseListeners.get(i); |
||||
_ctx.exitRule(listener); |
||||
listener.exitEveryRule(_ctx); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets the number of syntax errors reported during parsing. This value is |
||||
* incremented each time {@link #notifyErrorListeners} is called. |
||||
* |
||||
* @see #notifyErrorListeners |
||||
*/ |
||||
public int getNumberOfSyntaxErrors() { |
||||
return _syntaxErrors; |
||||
} |
||||
|
||||
@Override |
||||
public TokenFactory<?> getTokenFactory() { |
||||
return _input.getTokenSource().getTokenFactory(); |
||||
} |
||||
|
||||
/** Tell our token source and error strategy about a new way to create tokens. */ |
||||
@Override |
||||
public void setTokenFactory(TokenFactory<?> factory) { |
||||
_input.getTokenSource().setTokenFactory(factory); |
||||
} |
||||
|
||||
/** |
||||
* The ATN with bypass alternatives is expensive to create so we create it |
||||
* lazily. |
||||
* |
||||
* @throws UnsupportedOperationException if the current parser does not |
||||
* implement the {@link #getSerializedATN()} method. |
||||
*/ |
||||
|
||||
public ATN getATNWithBypassAlts() { |
||||
String serializedAtn = getSerializedATN(); |
||||
if (serializedAtn == null) { |
||||
throw new UnsupportedOperationException("The current parser does not support an ATN with bypass alternatives."); |
||||
} |
||||
|
||||
synchronized (bypassAltsAtnCache) { |
||||
ATN result = bypassAltsAtnCache.get(serializedAtn); |
||||
if (result == null) { |
||||
ATNDeserializationOptions deserializationOptions = new ATNDeserializationOptions(); |
||||
deserializationOptions.setGenerateRuleBypassTransitions(true); |
||||
result = new ATNDeserializer(deserializationOptions).deserialize(serializedAtn.toCharArray()); |
||||
bypassAltsAtnCache.put(serializedAtn, result); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* The preferred method of getting a tree pattern. For example, here's a |
||||
* sample use: |
||||
* |
||||
* <pre> |
||||
* ParseTree t = parser.expr(); |
||||
* ParseTreePattern p = parser.compileParseTreePattern("<ID>+0", MyParser.RULE_expr); |
||||
* ParseTreeMatch m = p.match(t); |
||||
* String id = m.get("ID"); |
||||
* </pre> |
||||
*/ |
||||
public ParseTreePattern compileParseTreePattern(String pattern, int patternRuleIndex) { |
||||
if ( getTokenStream()!=null ) { |
||||
TokenSource tokenSource = getTokenStream().getTokenSource(); |
||||
if ( tokenSource instanceof Lexer ) { |
||||
Lexer lexer = (Lexer)tokenSource; |
||||
return compileParseTreePattern(pattern, patternRuleIndex, lexer); |
||||
} |
||||
} |
||||
throw new UnsupportedOperationException("Parser can't discover a lexer to use"); |
||||
} |
||||
|
||||
/** |
||||
* The same as {@link #compileParseTreePattern(String, int)} but specify a |
||||
* {@link Lexer} rather than trying to deduce it from this parser. |
||||
*/ |
||||
public ParseTreePattern compileParseTreePattern(String pattern, int patternRuleIndex, |
||||
Lexer lexer) |
||||
{ |
||||
ParseTreePatternMatcher m = new ParseTreePatternMatcher(lexer, this); |
||||
return m.compile(pattern, patternRuleIndex); |
||||
} |
||||
|
||||
|
||||
public ANTLRErrorStrategy getErrorHandler() { |
||||
return _errHandler; |
||||
} |
||||
|
||||
public void setErrorHandler(ANTLRErrorStrategy handler) { |
||||
this._errHandler = handler; |
||||
} |
||||
|
||||
@Override |
||||
public TokenStream getInputStream() { return getTokenStream(); } |
||||
|
||||
@Override |
||||
public final void setInputStream(IntStream input) { |
||||
setTokenStream((TokenStream)input); |
||||
} |
||||
|
||||
public TokenStream getTokenStream() { |
||||
return _input; |
||||
} |
||||
|
||||
/** Set the token stream and reset the parser. */ |
||||
public void setTokenStream(TokenStream input) { |
||||
this._input = null; |
||||
reset(); |
||||
this._input = input; |
||||
} |
||||
|
||||
/** Match needs to return the current input symbol, which gets put |
||||
* into the label for the associated token ref; e.g., x=ID. |
||||
*/ |
||||
|
||||
public Token getCurrentToken() { |
||||
return _input.LT(1); |
||||
} |
||||
|
||||
public final void notifyErrorListeners(String msg) { |
||||
notifyErrorListeners(getCurrentToken(), msg, null); |
||||
} |
||||
|
||||
public void notifyErrorListeners(Token offendingToken, String msg, |
||||
RecognitionException e) |
||||
{ |
||||
_syntaxErrors++; |
||||
int line = -1; |
||||
int charPositionInLine = -1; |
||||
line = offendingToken.getLine(); |
||||
charPositionInLine = offendingToken.getCharPositionInLine(); |
||||
|
||||
ANTLRErrorListener listener = getErrorListenerDispatch(); |
||||
listener.syntaxError(this, offendingToken, line, charPositionInLine, msg, e); |
||||
} |
||||
|
||||
/** |
||||
* Consume and return the {@linkplain #getCurrentToken current symbol}. |
||||
* |
||||
* <p>E.g., given the following input with {@code A} being the current |
||||
* lookahead symbol, this function moves the cursor to {@code B} and returns |
||||
* {@code A}.</p> |
||||
* |
||||
* <pre> |
||||
* A B |
||||
* ^ |
||||
* </pre> |
||||
* |
||||
* If the parser is not in error recovery mode, the consumed symbol is added |
||||
* to the parse tree using {@link ParserRuleContext#addChild(TerminalNode)}, and |
||||
* {@link ParseTreeListener#visitTerminal} is called on any parse listeners. |
||||
* If the parser <em>is</em> in error recovery mode, the consumed symbol is |
||||
* added to the parse tree using {@link #createErrorNode(ParserRuleContext, Token)} then |
||||
* {@link ParserRuleContext#addErrorNode(ErrorNode)} and |
||||
* {@link ParseTreeListener#visitErrorNode} is called on any parse |
||||
* listeners. |
||||
*/ |
||||
public Token consume() { |
||||
Token o = getCurrentToken(); |
||||
if (o.getType() != EOF) { |
||||
getInputStream().consume(); |
||||
} |
||||
boolean hasListener = _parseListeners != null && !_parseListeners.isEmpty(); |
||||
if (_buildParseTrees || hasListener) { |
||||
if ( _errHandler.inErrorRecoveryMode(this) ) { |
||||
ErrorNode node = _ctx.addErrorNode(createErrorNode(_ctx,o)); |
||||
if (_parseListeners != null) { |
||||
for (ParseTreeListener listener : _parseListeners) { |
||||
listener.visitErrorNode(node); |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
TerminalNode node = _ctx.addChild(createTerminalNode(_ctx,o)); |
||||
if (_parseListeners != null) { |
||||
for (ParseTreeListener listener : _parseListeners) { |
||||
listener.visitTerminal(node); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return o; |
||||
} |
||||
|
||||
/** How to create a token leaf node associated with a parent. |
||||
* Typically, the terminal node to create is not a function of the parent. |
||||
* |
||||
* @since 4.7 |
||||
*/ |
||||
public TerminalNode createTerminalNode(ParserRuleContext parent, Token t) { |
||||
return new TerminalNodeImpl(t); |
||||
} |
||||
|
||||
/** How to create an error node, given a token, associated with a parent. |
||||
* Typically, the error node to create is not a function of the parent. |
||||
* |
||||
* @since 4.7 |
||||
*/ |
||||
public ErrorNode createErrorNode(ParserRuleContext parent, Token t) { |
||||
return new ErrorNodeImpl(t); |
||||
} |
||||
|
||||
protected void addContextToParseTree() { |
||||
ParserRuleContext parent = (ParserRuleContext)_ctx.parent; |
||||
// add current context to parent if we have a parent
|
||||
if ( parent!=null ) { |
||||
parent.addChild(_ctx); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Always called by generated parsers upon entry to a rule. Access field |
||||
* {@link #_ctx} get the current context. |
||||
*/ |
||||
public void enterRule(ParserRuleContext localctx, int state, int ruleIndex) { |
||||
setState(state); |
||||
_ctx = localctx; |
||||
_ctx.start = _input.LT(1); |
||||
if (_buildParseTrees) addContextToParseTree(); |
||||
if ( _parseListeners != null) triggerEnterRuleEvent(); |
||||
} |
||||
|
||||
public void exitRule() { |
||||
if ( matchedEOF ) { |
||||
// if we have matched EOF, it cannot consume past EOF so we use LT(1) here
|
||||
_ctx.stop = _input.LT(1); // LT(1) will be end of file
|
||||
} |
||||
else { |
||||
_ctx.stop = _input.LT(-1); // stop node is what we just matched
|
||||
} |
||||
// trigger event on _ctx, before it reverts to parent
|
||||
if ( _parseListeners != null) triggerExitRuleEvent(); |
||||
setState(_ctx.invokingState); |
||||
_ctx = (ParserRuleContext)_ctx.parent; |
||||
} |
||||
|
||||
public void enterOuterAlt(ParserRuleContext localctx, int altNum) { |
||||
localctx.setAltNumber(altNum); |
||||
// if we have new localctx, make sure we replace existing ctx
|
||||
// that is previous child of parse tree
|
||||
if ( _buildParseTrees && _ctx != localctx ) { |
||||
ParserRuleContext parent = (ParserRuleContext)_ctx.parent; |
||||
if ( parent!=null ) { |
||||
parent.removeLastChild(); |
||||
parent.addChild(localctx); |
||||
} |
||||
} |
||||
_ctx = localctx; |
||||
} |
||||
|
||||
/** |
||||
* Get the precedence level for the top-most precedence rule. |
||||
* |
||||
* @return The precedence level for the top-most precedence rule, or -1 if |
||||
* the parser context is not nested within a precedence rule. |
||||
*/ |
||||
public final int getPrecedence() { |
||||
if (_precedenceStack.isEmpty()) { |
||||
return -1; |
||||
} |
||||
|
||||
return _precedenceStack.peek(); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated Use |
||||
* {@link #enterRecursionRule(ParserRuleContext, int, int, int)} instead. |
||||
*/ |
||||
@Deprecated |
||||
public void enterRecursionRule(ParserRuleContext localctx, int ruleIndex) { |
||||
enterRecursionRule(localctx, getATN().ruleToStartState[ruleIndex].stateNumber, ruleIndex, 0); |
||||
} |
||||
|
||||
public void enterRecursionRule(ParserRuleContext localctx, int state, int ruleIndex, int precedence) { |
||||
setState(state); |
||||
_precedenceStack.push(precedence); |
||||
_ctx = localctx; |
||||
_ctx.start = _input.LT(1); |
||||
if (_parseListeners != null) { |
||||
triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
|
||||
} |
||||
} |
||||
|
||||
/** Like {@link #enterRule} but for recursive rules. |
||||
* Make the current context the child of the incoming localctx. |
||||
*/ |
||||
public void pushNewRecursionContext(ParserRuleContext localctx, int state, int ruleIndex) { |
||||
ParserRuleContext previous = _ctx; |
||||
previous.parent = localctx; |
||||
previous.invokingState = state; |
||||
previous.stop = _input.LT(-1); |
||||
|
||||
_ctx = localctx; |
||||
_ctx.start = previous.start; |
||||
if (_buildParseTrees) { |
||||
_ctx.addChild(previous); |
||||
} |
||||
|
||||
if ( _parseListeners != null ) { |
||||
triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
|
||||
} |
||||
} |
||||
|
||||
public void unrollRecursionContexts(ParserRuleContext _parentctx) { |
||||
_precedenceStack.pop(); |
||||
_ctx.stop = _input.LT(-1); |
||||
ParserRuleContext retctx = _ctx; // save current ctx (return value)
|
||||
|
||||
// unroll so _ctx is as it was before call to recursive method
|
||||
if ( _parseListeners != null ) { |
||||
while ( _ctx != _parentctx ) { |
||||
triggerExitRuleEvent(); |
||||
_ctx = (ParserRuleContext)_ctx.parent; |
||||
} |
||||
} |
||||
else { |
||||
_ctx = _parentctx; |
||||
} |
||||
|
||||
// hook into tree
|
||||
retctx.parent = _parentctx; |
||||
|
||||
if (_buildParseTrees && _parentctx != null) { |
||||
// add return ctx into invoking rule's tree
|
||||
_parentctx.addChild(retctx); |
||||
} |
||||
} |
||||
|
||||
public ParserRuleContext getInvokingContext(int ruleIndex) { |
||||
ParserRuleContext p = _ctx; |
||||
while ( p!=null ) { |
||||
if ( p.getRuleIndex() == ruleIndex ) return p; |
||||
p = (ParserRuleContext)p.parent; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public ParserRuleContext getContext() { |
||||
return _ctx; |
||||
} |
||||
|
||||
public void setContext(ParserRuleContext ctx) { |
||||
_ctx = ctx; |
||||
} |
||||
|
||||
@Override |
||||
public boolean precpred(RuleContext localctx, int precedence) { |
||||
return precedence >= _precedenceStack.peek(); |
||||
} |
||||
|
||||
public boolean inContext(String context) { |
||||
// TODO: useful in parser?
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether or not {@code symbol} can follow the current state in the |
||||
* ATN. The behavior of this method is equivalent to the following, but is |
||||
* implemented such that the complete context-sensitive follow set does not |
||||
* need to be explicitly constructed. |
||||
* |
||||
* <pre> |
||||
* return getExpectedTokens().contains(symbol); |
||||
* </pre> |
||||
* |
||||
* @param symbol the symbol type to check |
||||
* @return {@code true} if {@code symbol} can follow the current state in |
||||
* the ATN, otherwise {@code false}. |
||||
*/ |
||||
public boolean isExpectedToken(int symbol) { |
||||
// return getInterpreter().atn.nextTokens(_ctx);
|
||||
ATN atn = getInterpreter().atn; |
||||
ParserRuleContext ctx = _ctx; |
||||
ATNState s = atn.states.get(getState()); |
||||
IntervalSet following = atn.nextTokens(s); |
||||
if (following.contains(symbol)) { |
||||
return true; |
||||
} |
||||
// System.out.println("following "+s+"="+following);
|
||||
if ( !following.contains(Token.EPSILON) ) return false; |
||||
|
||||
while ( ctx!=null && ctx.invokingState>=0 && following.contains(Token.EPSILON) ) { |
||||
ATNState invokingState = atn.states.get(ctx.invokingState); |
||||
RuleTransition rt = (RuleTransition)invokingState.transition(0); |
||||
following = atn.nextTokens(rt.followState); |
||||
if (following.contains(symbol)) { |
||||
return true; |
||||
} |
||||
|
||||
ctx = (ParserRuleContext)ctx.parent; |
||||
} |
||||
|
||||
if ( following.contains(Token.EPSILON) && symbol == Token.EOF ) { |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public boolean isMatchedEOF() { |
||||
return matchedEOF; |
||||
} |
||||
|
||||
/** |
||||
* Computes the set of input symbols which could follow the current parser |
||||
* state and context, as given by {@link #getState} and {@link #getContext}, |
||||
* respectively. |
||||
* |
||||
* @see ATN#getExpectedTokens(int, RuleContext) |
||||
*/ |
||||
public IntervalSet getExpectedTokens() { |
||||
return getATN().getExpectedTokens(getState(), getContext()); |
||||
} |
||||
|
||||
|
||||
public IntervalSet getExpectedTokensWithinCurrentRule() { |
||||
ATN atn = getInterpreter().atn; |
||||
ATNState s = atn.states.get(getState()); |
||||
return atn.nextTokens(s); |
||||
} |
||||
|
||||
/** Get a rule's index (i.e., {@code RULE_ruleName} field) or -1 if not found. */ |
||||
public int getRuleIndex(String ruleName) { |
||||
Integer ruleIndex = getRuleIndexMap().get(ruleName); |
||||
if ( ruleIndex!=null ) return ruleIndex; |
||||
return -1; |
||||
} |
||||
|
||||
public ParserRuleContext getRuleContext() { return _ctx; } |
||||
|
||||
/** Return List<String> of the rule names in your parser instance |
||||
* leading up to a call to the current rule. You could override if |
||||
* you want more details such as the file/line info of where |
||||
* in the ATN a rule is invoked. |
||||
* |
||||
* This is very useful for error messages. |
||||
*/ |
||||
public List<String> getRuleInvocationStack() { |
||||
return getRuleInvocationStack(_ctx); |
||||
} |
||||
|
||||
public List<String> getRuleInvocationStack(RuleContext p) { |
||||
String[] ruleNames = getRuleNames(); |
||||
List<String> stack = new ArrayList<String>(); |
||||
while ( p!=null ) { |
||||
// compute what follows who invoked us
|
||||
int ruleIndex = p.getRuleIndex(); |
||||
if ( ruleIndex<0 ) stack.add("n/a"); |
||||
else stack.add(ruleNames[ruleIndex]); |
||||
p = p.parent; |
||||
} |
||||
return stack; |
||||
} |
||||
|
||||
/** For debugging and other purposes. */ |
||||
public List<String> getDFAStrings() { |
||||
synchronized (_interp.decisionToDFA) { |
||||
List<String> s = new ArrayList<String>(); |
||||
for (int d = 0; d < _interp.decisionToDFA.length; d++) { |
||||
DFA dfa = _interp.decisionToDFA[d]; |
||||
s.add( dfa.toString(getVocabulary()) ); |
||||
} |
||||
return s; |
||||
} |
||||
} |
||||
|
||||
/** For debugging and other purposes. */ |
||||
public void dumpDFA() { |
||||
synchronized (_interp.decisionToDFA) { |
||||
boolean seenOne = false; |
||||
for (int d = 0; d < _interp.decisionToDFA.length; d++) { |
||||
DFA dfa = _interp.decisionToDFA[d]; |
||||
if ( !dfa.states.isEmpty() ) { |
||||
if ( seenOne ) System.out.println(); |
||||
System.out.println("Decision " + dfa.decision + ":"); |
||||
System.out.print(dfa.toString(getVocabulary())); |
||||
seenOne = true; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public String getSourceName() { |
||||
return _input.getSourceName(); |
||||
} |
||||
|
||||
@Override |
||||
public ParseInfo getParseInfo() { |
||||
ParserATNSimulator interp = getInterpreter(); |
||||
if (interp instanceof ProfilingATNSimulator) { |
||||
return new ParseInfo((ProfilingATNSimulator)interp); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* @since 4.3 |
||||
*/ |
||||
public void setProfile(boolean profile) { |
||||
ParserATNSimulator interp = getInterpreter(); |
||||
PredictionMode saveMode = interp.getPredictionMode(); |
||||
if ( profile ) { |
||||
if ( !(interp instanceof ProfilingATNSimulator) ) { |
||||
setInterpreter(new ProfilingATNSimulator(this)); |
||||
} |
||||
} |
||||
else if ( interp instanceof ProfilingATNSimulator ) { |
||||
ParserATNSimulator sim = |
||||
new ParserATNSimulator(this, getATN(), interp.decisionToDFA, interp.getSharedContextCache()); |
||||
setInterpreter(sim); |
||||
} |
||||
getInterpreter().setPredictionMode(saveMode); |
||||
} |
||||
|
||||
/** During a parse is sometimes useful to listen in on the rule entry and exit |
||||
* events as well as token matches. This is for quick and dirty debugging. |
||||
*/ |
||||
public void setTrace(boolean trace) { |
||||
if ( !trace ) { |
||||
removeParseListener(_tracer); |
||||
_tracer = null; |
||||
} |
||||
else { |
||||
if ( _tracer!=null ) removeParseListener(_tracer); |
||||
else _tracer = new TraceListener(); |
||||
addParseListener(_tracer); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets whether a {@link TraceListener} is registered as a parse listener |
||||
* for the parser. |
||||
* |
||||
* @see #setTrace(boolean) |
||||
*/ |
||||
public boolean isTrace() { |
||||
return _tracer != null; |
||||
} |
||||
} |
||||
|
@ -1,451 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATN; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNState; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ActionTransition; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.AtomTransition; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.DecisionState; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.LoopEndState; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ParserATNSimulator; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.PrecedencePredicateTransition; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.PredicateTransition; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.PredictionContextCache; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.RuleStartState; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.RuleTransition; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.StarLoopEntryState; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.Transition; |
||||
import com.fr.third.org.antlr.v4.runtime.dfa.DFA; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Pair; |
||||
|
||||
import java.util.ArrayDeque; |
||||
import java.util.Collection; |
||||
import java.util.Deque; |
||||
|
||||
/** A parser simulator that mimics what ANTLR's generated |
||||
* parser code does. A ParserATNSimulator is used to make |
||||
* predictions via adaptivePredict but this class moves a pointer through the |
||||
* ATN to simulate parsing. ParserATNSimulator just |
||||
* makes us efficient rather than having to backtrack, for example. |
||||
* |
||||
* This properly creates parse trees even for left recursive rules. |
||||
* |
||||
* We rely on the left recursive rule invocation and special predicate |
||||
* transitions to make left recursive rules work. |
||||
* |
||||
* See TestParserInterpreter for examples. |
||||
*/ |
||||
public class ParserInterpreter extends Parser { |
||||
protected final String grammarFileName; |
||||
protected final ATN atn; |
||||
|
||||
protected final DFA[] decisionToDFA; // not shared like it is for generated parsers
|
||||
protected final PredictionContextCache sharedContextCache = new PredictionContextCache(); |
||||
|
||||
@Deprecated |
||||
protected final String[] tokenNames; |
||||
protected final String[] ruleNames; |
||||
|
||||
private final Vocabulary vocabulary; |
||||
|
||||
/** This stack corresponds to the _parentctx, _parentState pair of locals |
||||
* that would exist on call stack frames with a recursive descent parser; |
||||
* in the generated function for a left-recursive rule you'd see: |
||||
* |
||||
* private EContext e(int _p) throws RecognitionException { |
||||
* ParserRuleContext _parentctx = _ctx; // Pair.a
|
||||
* int _parentState = getState(); // Pair.b
|
||||
* ... |
||||
* } |
||||
* |
||||
* Those values are used to create new recursive rule invocation contexts |
||||
* associated with left operand of an alt like "expr '*' expr". |
||||
*/ |
||||
protected final Deque<Pair<ParserRuleContext, Integer>> _parentContextStack = |
||||
new ArrayDeque<Pair<ParserRuleContext, Integer>>(); |
||||
|
||||
/** We need a map from (decision,inputIndex)->forced alt for computing ambiguous |
||||
* parse trees. For now, we allow exactly one override. |
||||
*/ |
||||
protected int overrideDecision = -1; |
||||
protected int overrideDecisionInputIndex = -1; |
||||
protected int overrideDecisionAlt = -1; |
||||
protected boolean overrideDecisionReached = false; // latch and only override once; error might trigger infinite loop
|
||||
|
||||
/** What is the current context when we override a decisions? This tells |
||||
* us what the root of the parse tree is when using override |
||||
* for an ambiguity/lookahead check. |
||||
*/ |
||||
protected InterpreterRuleContext overrideDecisionRoot = null; |
||||
|
||||
|
||||
protected InterpreterRuleContext rootContext; |
||||
|
||||
/** |
||||
* @deprecated Use {@link #ParserInterpreter(String, Vocabulary, Collection, ATN, TokenStream)} instead. |
||||
*/ |
||||
@Deprecated |
||||
public ParserInterpreter(String grammarFileName, Collection<String> tokenNames, |
||||
Collection<String> ruleNames, ATN atn, TokenStream input) { |
||||
this(grammarFileName, VocabularyImpl.fromTokenNames(tokenNames.toArray(new String[tokenNames.size()])), ruleNames, atn, input); |
||||
} |
||||
|
||||
public ParserInterpreter(String grammarFileName, Vocabulary vocabulary, |
||||
Collection<String> ruleNames, ATN atn, TokenStream input) |
||||
{ |
||||
super(input); |
||||
this.grammarFileName = grammarFileName; |
||||
this.atn = atn; |
||||
this.tokenNames = new String[atn.maxTokenType]; |
||||
for (int i = 0; i < tokenNames.length; i++) { |
||||
tokenNames[i] = vocabulary.getDisplayName(i); |
||||
} |
||||
|
||||
this.ruleNames = ruleNames.toArray(new String[ruleNames.size()]); |
||||
this.vocabulary = vocabulary; |
||||
|
||||
// init decision DFA
|
||||
int numberOfDecisions = atn.getNumberOfDecisions(); |
||||
this.decisionToDFA = new DFA[numberOfDecisions]; |
||||
for (int i = 0; i < numberOfDecisions; i++) { |
||||
DecisionState decisionState = atn.getDecisionState(i); |
||||
decisionToDFA[i] = new DFA(decisionState, i); |
||||
} |
||||
|
||||
// get atn simulator that knows how to do predictions
|
||||
setInterpreter(new ParserATNSimulator(this, atn, |
||||
decisionToDFA, |
||||
sharedContextCache)); |
||||
} |
||||
|
||||
@Override |
||||
public void reset() { |
||||
super.reset(); |
||||
overrideDecisionReached = false; |
||||
overrideDecisionRoot = null; |
||||
} |
||||
|
||||
@Override |
||||
public ATN getATN() { |
||||
return atn; |
||||
} |
||||
|
||||
@Override |
||||
@Deprecated |
||||
public String[] getTokenNames() { |
||||
return tokenNames; |
||||
} |
||||
|
||||
@Override |
||||
public Vocabulary getVocabulary() { |
||||
return vocabulary; |
||||
} |
||||
|
||||
@Override |
||||
public String[] getRuleNames() { |
||||
return ruleNames; |
||||
} |
||||
|
||||
@Override |
||||
public String getGrammarFileName() { |
||||
return grammarFileName; |
||||
} |
||||
|
||||
/** Begin parsing at startRuleIndex */ |
||||
public ParserRuleContext parse(int startRuleIndex) { |
||||
RuleStartState startRuleStartState = atn.ruleToStartState[startRuleIndex]; |
||||
|
||||
rootContext = createInterpreterRuleContext(null, ATNState.INVALID_STATE_NUMBER, startRuleIndex); |
||||
if (startRuleStartState.isLeftRecursiveRule) { |
||||
enterRecursionRule(rootContext, startRuleStartState.stateNumber, startRuleIndex, 0); |
||||
} |
||||
else { |
||||
enterRule(rootContext, startRuleStartState.stateNumber, startRuleIndex); |
||||
} |
||||
|
||||
while ( true ) { |
||||
ATNState p = getATNState(); |
||||
switch ( p.getStateType() ) { |
||||
case ATNState.RULE_STOP : |
||||
// pop; return from rule
|
||||
if ( _ctx.isEmpty() ) { |
||||
if (startRuleStartState.isLeftRecursiveRule) { |
||||
ParserRuleContext result = _ctx; |
||||
Pair<ParserRuleContext, Integer> parentContext = _parentContextStack.pop(); |
||||
unrollRecursionContexts(parentContext.a); |
||||
return result; |
||||
} |
||||
else { |
||||
exitRule(); |
||||
return rootContext; |
||||
} |
||||
} |
||||
|
||||
visitRuleStopState(p); |
||||
break; |
||||
|
||||
default : |
||||
try { |
||||
visitState(p); |
||||
} |
||||
catch (RecognitionException e) { |
||||
setState(atn.ruleToStopState[p.ruleIndex].stateNumber); |
||||
getContext().exception = e; |
||||
getErrorHandler().reportError(this, e); |
||||
recover(e); |
||||
} |
||||
|
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void enterRecursionRule(ParserRuleContext localctx, int state, int ruleIndex, int precedence) { |
||||
Pair<ParserRuleContext, Integer> pair = new Pair<ParserRuleContext, Integer>(_ctx, localctx.invokingState); |
||||
_parentContextStack.push(pair); |
||||
super.enterRecursionRule(localctx, state, ruleIndex, precedence); |
||||
} |
||||
|
||||
protected ATNState getATNState() { |
||||
return atn.states.get(getState()); |
||||
} |
||||
|
||||
protected void visitState(ATNState p) { |
||||
// System.out.println("visitState "+p.stateNumber);
|
||||
int predictedAlt = 1; |
||||
if ( p instanceof DecisionState ) { |
||||
predictedAlt = visitDecisionState((DecisionState) p); |
||||
} |
||||
|
||||
Transition transition = p.transition(predictedAlt - 1); |
||||
switch (transition.getSerializationType()) { |
||||
case Transition.EPSILON: |
||||
if ( p.getStateType()==ATNState.STAR_LOOP_ENTRY && |
||||
((StarLoopEntryState)p).isPrecedenceDecision && |
||||
!(transition.target instanceof LoopEndState)) |
||||
{ |
||||
// We are at the start of a left recursive rule's (...)* loop
|
||||
// and we're not taking the exit branch of loop.
|
||||
InterpreterRuleContext localctx = |
||||
createInterpreterRuleContext(_parentContextStack.peek().a, |
||||
_parentContextStack.peek().b, |
||||
_ctx.getRuleIndex()); |
||||
pushNewRecursionContext(localctx, |
||||
atn.ruleToStartState[p.ruleIndex].stateNumber, |
||||
_ctx.getRuleIndex()); |
||||
} |
||||
break; |
||||
|
||||
case Transition.ATOM: |
||||
match(((AtomTransition)transition).label); |
||||
break; |
||||
|
||||
case Transition.RANGE: |
||||
case Transition.SET: |
||||
case Transition.NOT_SET: |
||||
if (!transition.matches(_input.LA(1), Token.MIN_USER_TOKEN_TYPE, 65535)) { |
||||
recoverInline(); |
||||
} |
||||
matchWildcard(); |
||||
break; |
||||
|
||||
case Transition.WILDCARD: |
||||
matchWildcard(); |
||||
break; |
||||
|
||||
case Transition.RULE: |
||||
RuleStartState ruleStartState = (RuleStartState)transition.target; |
||||
int ruleIndex = ruleStartState.ruleIndex; |
||||
InterpreterRuleContext newctx = createInterpreterRuleContext(_ctx, p.stateNumber, ruleIndex); |
||||
if (ruleStartState.isLeftRecursiveRule) { |
||||
enterRecursionRule(newctx, ruleStartState.stateNumber, ruleIndex, ((RuleTransition)transition).precedence); |
||||
} |
||||
else { |
||||
enterRule(newctx, transition.target.stateNumber, ruleIndex); |
||||
} |
||||
break; |
||||
|
||||
case Transition.PREDICATE: |
||||
PredicateTransition predicateTransition = (PredicateTransition)transition; |
||||
if (!sempred(_ctx, predicateTransition.ruleIndex, predicateTransition.predIndex)) { |
||||
throw new FailedPredicateException(this); |
||||
} |
||||
|
||||
break; |
||||
|
||||
case Transition.ACTION: |
||||
ActionTransition actionTransition = (ActionTransition)transition; |
||||
action(_ctx, actionTransition.ruleIndex, actionTransition.actionIndex); |
||||
break; |
||||
|
||||
case Transition.PRECEDENCE: |
||||
if (!precpred(_ctx, ((PrecedencePredicateTransition)transition).precedence)) { |
||||
throw new FailedPredicateException(this, String.format("precpred(_ctx, %d)", ((PrecedencePredicateTransition)transition).precedence)); |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
throw new UnsupportedOperationException("Unrecognized ATN transition type."); |
||||
} |
||||
|
||||
setState(transition.target.stateNumber); |
||||
} |
||||
|
||||
/** Method visitDecisionState() is called when the interpreter reaches |
||||
* a decision state (instance of DecisionState). It gives an opportunity |
||||
* for subclasses to track interesting things. |
||||
*/ |
||||
protected int visitDecisionState(DecisionState p) { |
||||
int predictedAlt = 1; |
||||
if ( p.getNumberOfTransitions()>1 ) { |
||||
getErrorHandler().sync(this); |
||||
int decision = p.decision; |
||||
if ( decision == overrideDecision && _input.index() == overrideDecisionInputIndex && |
||||
!overrideDecisionReached ) |
||||
{ |
||||
predictedAlt = overrideDecisionAlt; |
||||
overrideDecisionReached = true; |
||||
} |
||||
else { |
||||
predictedAlt = getInterpreter().adaptivePredict(_input, decision, _ctx); |
||||
} |
||||
} |
||||
return predictedAlt; |
||||
} |
||||
|
||||
/** Provide simple "factory" for InterpreterRuleContext's. |
||||
* @since 4.5.1 |
||||
*/ |
||||
protected InterpreterRuleContext createInterpreterRuleContext( |
||||
ParserRuleContext parent, |
||||
int invokingStateNumber, |
||||
int ruleIndex) |
||||
{ |
||||
return new InterpreterRuleContext(parent, invokingStateNumber, ruleIndex); |
||||
} |
||||
|
||||
protected void visitRuleStopState(ATNState p) { |
||||
RuleStartState ruleStartState = atn.ruleToStartState[p.ruleIndex]; |
||||
if (ruleStartState.isLeftRecursiveRule) { |
||||
Pair<ParserRuleContext, Integer> parentContext = _parentContextStack.pop(); |
||||
unrollRecursionContexts(parentContext.a); |
||||
setState(parentContext.b); |
||||
} |
||||
else { |
||||
exitRule(); |
||||
} |
||||
|
||||
RuleTransition ruleTransition = (RuleTransition)atn.states.get(getState()).transition(0); |
||||
setState(ruleTransition.followState.stateNumber); |
||||
} |
||||
|
||||
/** Override this parser interpreters normal decision-making process |
||||
* at a particular decision and input token index. Instead of |
||||
* allowing the adaptive prediction mechanism to choose the |
||||
* first alternative within a block that leads to a successful parse, |
||||
* force it to take the alternative, 1..n for n alternatives. |
||||
* |
||||
* As an implementation limitation right now, you can only specify one |
||||
* override. This is sufficient to allow construction of different |
||||
* parse trees for ambiguous input. It means re-parsing the entire input |
||||
* in general because you're never sure where an ambiguous sequence would |
||||
* live in the various parse trees. For example, in one interpretation, |
||||
* an ambiguous input sequence would be matched completely in expression |
||||
* but in another it could match all the way back to the root. |
||||
* |
||||
* s : e '!'? ; |
||||
* e : ID |
||||
* | ID '!' |
||||
* ; |
||||
* |
||||
* Here, x! can be matched as (s (e ID) !) or (s (e ID !)). In the first |
||||
* case, the ambiguous sequence is fully contained only by the root. |
||||
* In the second case, the ambiguous sequences fully contained within just |
||||
* e, as in: (e ID !). |
||||
* |
||||
* Rather than trying to optimize this and make |
||||
* some intelligent decisions for optimization purposes, I settled on |
||||
* just re-parsing the whole input and then using |
||||
* {link Trees#getRootOfSubtreeEnclosingRegion} to find the minimal |
||||
* subtree that contains the ambiguous sequence. I originally tried to |
||||
* record the call stack at the point the parser detected and ambiguity but |
||||
* left recursive rules create a parse tree stack that does not reflect |
||||
* the actual call stack. That impedance mismatch was enough to make |
||||
* it it challenging to restart the parser at a deeply nested rule |
||||
* invocation. |
||||
* |
||||
* Only parser interpreters can override decisions so as to avoid inserting |
||||
* override checking code in the critical ALL(*) prediction execution path. |
||||
* |
||||
* @since 4.5.1 |
||||
*/ |
||||
public void addDecisionOverride(int decision, int tokenIndex, int forcedAlt) { |
||||
overrideDecision = decision; |
||||
overrideDecisionInputIndex = tokenIndex; |
||||
overrideDecisionAlt = forcedAlt; |
||||
} |
||||
|
||||
public InterpreterRuleContext getOverrideDecisionRoot() { |
||||
return overrideDecisionRoot; |
||||
} |
||||
|
||||
/** Rely on the error handler for this parser but, if no tokens are consumed |
||||
* to recover, add an error node. Otherwise, nothing is seen in the parse |
||||
* tree. |
||||
*/ |
||||
protected void recover(RecognitionException e) { |
||||
int i = _input.index(); |
||||
getErrorHandler().recover(this, e); |
||||
if ( _input.index()==i ) { |
||||
// no input consumed, better add an error node
|
||||
if ( e instanceof InputMismatchException ) { |
||||
InputMismatchException ime = (InputMismatchException)e; |
||||
Token tok = e.getOffendingToken(); |
||||
int expectedTokenType = Token.INVALID_TYPE; |
||||
if ( !ime.getExpectedTokens().isNil() ) { |
||||
expectedTokenType = ime.getExpectedTokens().getMinElement(); // get any element
|
||||
} |
||||
Token errToken = |
||||
getTokenFactory().create(new Pair<TokenSource, CharStream>(tok.getTokenSource(), tok.getTokenSource().getInputStream()), |
||||
expectedTokenType, tok.getText(), |
||||
Token.DEFAULT_CHANNEL, |
||||
-1, -1, // invalid start/stop
|
||||
tok.getLine(), tok.getCharPositionInLine()); |
||||
_ctx.addErrorNode(createErrorNode(_ctx,errToken)); |
||||
} |
||||
else { // NoViableAlt
|
||||
Token tok = e.getOffendingToken(); |
||||
Token errToken = |
||||
getTokenFactory().create(new Pair<TokenSource, CharStream>(tok.getTokenSource(), tok.getTokenSource().getInputStream()), |
||||
Token.INVALID_TYPE, tok.getText(), |
||||
Token.DEFAULT_CHANNEL, |
||||
-1, -1, // invalid start/stop
|
||||
tok.getLine(), tok.getCharPositionInLine()); |
||||
_ctx.addErrorNode(createErrorNode(_ctx,errToken)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected Token recoverInline() { |
||||
return _errHandler.recoverInline(this); |
||||
} |
||||
|
||||
/** Return the root of the parse, which can be useful if the parser |
||||
* bails out. You still can access the top node. Note that, |
||||
* because of the way left recursive rules add children, it's possible |
||||
* that the root will not have any children if the start rule immediately |
||||
* called and left recursive rule that fails. |
||||
* |
||||
* @since 4.5.1 |
||||
*/ |
||||
public InterpreterRuleContext getRootContext() { |
||||
return rootContext; |
||||
} |
||||
} |
||||
|
@ -1,338 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.ErrorNode; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.ErrorNodeImpl; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.ParseTree; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.ParseTreeListener; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.TerminalNode; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.TerminalNodeImpl; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
/** A rule invocation record for parsing. |
||||
* |
||||
* Contains all of the information about the current rule not stored in the |
||||
* RuleContext. It handles parse tree children list, Any ATN state |
||||
* tracing, and the default values available for rule invocations: |
||||
* start, stop, rule index, current alt number. |
||||
* |
||||
* Subclasses made for each rule and grammar track the parameters, |
||||
* return values, locals, and labels specific to that rule. These |
||||
* are the objects that are returned from rules. |
||||
* |
||||
* Note text is not an actual field of a rule return value; it is computed |
||||
* from start and stop using the input stream's toString() method. I |
||||
* could add a ctor to this so that we can pass in and store the input |
||||
* stream, but I'm not sure we want to do that. It would seem to be undefined |
||||
* to get the .text property anyway if the rule matches tokens from multiple |
||||
* input streams. |
||||
* |
||||
* I do not use getters for fields of objects that are used simply to |
||||
* group values such as this aggregate. The getters/setters are there to |
||||
* satisfy the superclass interface. |
||||
*/ |
||||
public class ParserRuleContext extends RuleContext { |
||||
/** If we are debugging or building a parse tree for a visitor, |
||||
* we need to track all of the tokens and rule invocations associated |
||||
* with this rule's context. This is empty for parsing w/o tree constr. |
||||
* operation because we don't the need to track the details about |
||||
* how we parse this rule. |
||||
*/ |
||||
public List<ParseTree> children; |
||||
|
||||
/** For debugging/tracing purposes, we want to track all of the nodes in |
||||
* the ATN traversed by the parser for a particular rule. |
||||
* This list indicates the sequence of ATN nodes used to match |
||||
* the elements of the children list. This list does not include |
||||
* ATN nodes and other rules used to match rule invocations. It |
||||
* traces the rule invocation node itself but nothing inside that |
||||
* other rule's ATN submachine. |
||||
* |
||||
* There is NOT a one-to-one correspondence between the children and |
||||
* states list. There are typically many nodes in the ATN traversed |
||||
* for each element in the children list. For example, for a rule |
||||
* invocation there is the invoking state and the following state. |
||||
* |
||||
* The parser setState() method updates field s and adds it to this list |
||||
* if we are debugging/tracing. |
||||
* |
||||
* This does not trace states visited during prediction. |
||||
*/ |
||||
// public List<Integer> states;
|
||||
|
||||
public Token start, stop; |
||||
|
||||
/** |
||||
* The exception that forced this rule to return. If the rule successfully |
||||
* completed, this is {@code null}. |
||||
*/ |
||||
public RecognitionException exception; |
||||
|
||||
public ParserRuleContext() { } |
||||
|
||||
/** COPY a ctx (I'm deliberately not using copy constructor) to avoid |
||||
* confusion with creating node with parent. Does not copy children |
||||
* (except error leaves). |
||||
* |
||||
* This is used in the generated parser code to flip a generic XContext |
||||
* node for rule X to a YContext for alt label Y. In that sense, it is |
||||
* not really a generic copy function. |
||||
* |
||||
* If we do an error sync() at start of a rule, we might add error nodes |
||||
* to the generic XContext so this function must copy those nodes to |
||||
* the YContext as well else they are lost! |
||||
*/ |
||||
public void copyFrom(ParserRuleContext ctx) { |
||||
this.parent = ctx.parent; |
||||
this.invokingState = ctx.invokingState; |
||||
|
||||
this.start = ctx.start; |
||||
this.stop = ctx.stop; |
||||
|
||||
// copy any error nodes to alt label node
|
||||
if ( ctx.children!=null ) { |
||||
this.children = new ArrayList<>(); |
||||
// reset parent pointer for any error nodes
|
||||
for (ParseTree child : ctx.children) { |
||||
if ( child instanceof ErrorNode ) { |
||||
addChild((ErrorNode)child); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public ParserRuleContext(ParserRuleContext parent, int invokingStateNumber) { |
||||
super(parent, invokingStateNumber); |
||||
} |
||||
|
||||
// Double dispatch methods for listeners
|
||||
|
||||
public void enterRule(ParseTreeListener listener) { } |
||||
public void exitRule(ParseTreeListener listener) { } |
||||
|
||||
/** Add a parse tree node to this as a child. Works for |
||||
* internal and leaf nodes. Does not set parent link; |
||||
* other add methods must do that. Other addChild methods |
||||
* call this. |
||||
* |
||||
* We cannot set the parent pointer of the incoming node |
||||
* because the existing interfaces do not have a setParent() |
||||
* method and I don't want to break backward compatibility for this. |
||||
* |
||||
* @since 4.7 |
||||
*/ |
||||
public <T extends ParseTree> T addAnyChild(T t) { |
||||
if ( children==null ) children = new ArrayList<>(); |
||||
children.add(t); |
||||
return t; |
||||
} |
||||
|
||||
public RuleContext addChild(RuleContext ruleInvocation) { |
||||
return addAnyChild(ruleInvocation); |
||||
} |
||||
|
||||
/** Add a token leaf node child and force its parent to be this node. */ |
||||
public TerminalNode addChild(TerminalNode t) { |
||||
t.setParent(this); |
||||
return addAnyChild(t); |
||||
} |
||||
|
||||
/** Add an error node child and force its parent to be this node. |
||||
* |
||||
* @since 4.7 |
||||
*/ |
||||
public ErrorNode addErrorNode(ErrorNode errorNode) { |
||||
errorNode.setParent(this); |
||||
return addAnyChild(errorNode); |
||||
} |
||||
|
||||
/** Add a child to this node based upon matchedToken. It |
||||
* creates a TerminalNodeImpl rather than using |
||||
* {@link Parser#createTerminalNode(ParserRuleContext, Token)}. I'm leaving this |
||||
* in for compatibility but the parser doesn't use this anymore. |
||||
*/ |
||||
@Deprecated |
||||
public TerminalNode addChild(Token matchedToken) { |
||||
TerminalNodeImpl t = new TerminalNodeImpl(matchedToken); |
||||
addAnyChild(t); |
||||
t.setParent(this); |
||||
return t; |
||||
} |
||||
|
||||
/** Add a child to this node based upon badToken. It |
||||
* creates a ErrorNodeImpl rather than using |
||||
* {@link Parser#createErrorNode(ParserRuleContext, Token)}. I'm leaving this |
||||
* in for compatibility but the parser doesn't use this anymore. |
||||
*/ |
||||
@Deprecated |
||||
public ErrorNode addErrorNode(Token badToken) { |
||||
ErrorNodeImpl t = new ErrorNodeImpl(badToken); |
||||
addAnyChild(t); |
||||
t.setParent(this); |
||||
return t; |
||||
} |
||||
|
||||
// public void trace(int s) {
|
||||
// if ( states==null ) states = new ArrayList<Integer>();
|
||||
// states.add(s);
|
||||
// }
|
||||
|
||||
/** Used by enterOuterAlt to toss out a RuleContext previously added as |
||||
* we entered a rule. If we have # label, we will need to remove |
||||
* generic ruleContext object. |
||||
*/ |
||||
public void removeLastChild() { |
||||
if ( children!=null ) { |
||||
children.remove(children.size()-1); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
/** Override to make type more specific */ |
||||
public ParserRuleContext getParent() { |
||||
return (ParserRuleContext)super.getParent(); |
||||
} |
||||
|
||||
@Override |
||||
public ParseTree getChild(int i) { |
||||
return children!=null && i>=0 && i<children.size() ? children.get(i) : null; |
||||
} |
||||
|
||||
public <T extends ParseTree> T getChild(Class<? extends T> ctxType, int i) { |
||||
if ( children==null || i < 0 || i >= children.size() ) { |
||||
return null; |
||||
} |
||||
|
||||
int j = -1; // what element have we found with ctxType?
|
||||
for (ParseTree o : children) { |
||||
if ( ctxType.isInstance(o) ) { |
||||
j++; |
||||
if ( j == i ) { |
||||
return ctxType.cast(o); |
||||
} |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public TerminalNode getToken(int ttype, int i) { |
||||
if ( children==null || i < 0 || i >= children.size() ) { |
||||
return null; |
||||
} |
||||
|
||||
int j = -1; // what token with ttype have we found?
|
||||
for (ParseTree o : children) { |
||||
if ( o instanceof TerminalNode ) { |
||||
TerminalNode tnode = (TerminalNode)o; |
||||
Token symbol = tnode.getSymbol(); |
||||
if ( symbol.getType()==ttype ) { |
||||
j++; |
||||
if ( j == i ) { |
||||
return tnode; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
public List<TerminalNode> getTokens(int ttype) { |
||||
if ( children==null ) { |
||||
return Collections.emptyList(); |
||||
} |
||||
|
||||
List<TerminalNode> tokens = null; |
||||
for (ParseTree o : children) { |
||||
if ( o instanceof TerminalNode ) { |
||||
TerminalNode tnode = (TerminalNode)o; |
||||
Token symbol = tnode.getSymbol(); |
||||
if ( symbol.getType()==ttype ) { |
||||
if ( tokens==null ) { |
||||
tokens = new ArrayList<TerminalNode>(); |
||||
} |
||||
tokens.add(tnode); |
||||
} |
||||
} |
||||
} |
||||
|
||||
if ( tokens==null ) { |
||||
return Collections.emptyList(); |
||||
} |
||||
|
||||
return tokens; |
||||
} |
||||
|
||||
public <T extends ParserRuleContext> T getRuleContext(Class<? extends T> ctxType, int i) { |
||||
return getChild(ctxType, i); |
||||
} |
||||
|
||||
public <T extends ParserRuleContext> List<T> getRuleContexts(Class<? extends T> ctxType) { |
||||
if ( children==null ) { |
||||
return Collections.emptyList(); |
||||
} |
||||
|
||||
List<T> contexts = null; |
||||
for (ParseTree o : children) { |
||||
if ( ctxType.isInstance(o) ) { |
||||
if ( contexts==null ) { |
||||
contexts = new ArrayList<T>(); |
||||
} |
||||
|
||||
contexts.add(ctxType.cast(o)); |
||||
} |
||||
} |
||||
|
||||
if ( contexts==null ) { |
||||
return Collections.emptyList(); |
||||
} |
||||
|
||||
return contexts; |
||||
} |
||||
|
||||
@Override |
||||
public int getChildCount() { return children!=null ? children.size() : 0; } |
||||
|
||||
@Override |
||||
public Interval getSourceInterval() { |
||||
if ( start == null ) { |
||||
return Interval.INVALID; |
||||
} |
||||
if ( stop==null || stop.getTokenIndex()<start.getTokenIndex() ) { |
||||
return Interval.of(start.getTokenIndex(), start.getTokenIndex()-1); // empty
|
||||
} |
||||
return Interval.of(start.getTokenIndex(), stop.getTokenIndex()); |
||||
} |
||||
|
||||
/** |
||||
* Get the initial token in this context. |
||||
* Note that the range from start to stop is inclusive, so for rules that do not consume anything |
||||
* (for example, zero length or error productions) this token may exceed stop. |
||||
*/ |
||||
public Token getStart() { return start; } |
||||
/** |
||||
* Get the final token in this context. |
||||
* Note that the range from start to stop is inclusive, so for rules that do not consume anything |
||||
* (for example, zero length or error productions) this token may precede start. |
||||
*/ |
||||
public Token getStop() { return stop; } |
||||
|
||||
/** Used for rule context info debugging during parse-time, not so much for ATN debugging */ |
||||
public String toInfoString(Parser recognizer) { |
||||
List<String> rules = recognizer.getRuleInvocationStack(this); |
||||
Collections.reverse(rules); |
||||
return "ParserRuleContext"+rules+"{" + |
||||
"start=" + start + |
||||
", stop=" + stop + |
||||
'}'; |
||||
} |
||||
} |
||||
|
@ -1,84 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNConfigSet; |
||||
import com.fr.third.org.antlr.v4.runtime.dfa.DFA; |
||||
|
||||
import java.util.BitSet; |
||||
import java.util.Collection; |
||||
|
||||
/** |
||||
* This implementation of {@link ANTLRErrorListener} dispatches all calls to a |
||||
* collection of delegate listeners. This reduces the effort required to support multiple |
||||
* listeners. |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public class ProxyErrorListener implements ANTLRErrorListener { |
||||
private final Collection<? extends ANTLRErrorListener> delegates; |
||||
|
||||
public ProxyErrorListener(Collection<? extends ANTLRErrorListener> delegates) { |
||||
if (delegates == null) { |
||||
throw new NullPointerException("delegates"); |
||||
} |
||||
|
||||
this.delegates = delegates; |
||||
} |
||||
|
||||
@Override |
||||
public void syntaxError(Recognizer<?, ?> recognizer, |
||||
Object offendingSymbol, |
||||
int line, |
||||
int charPositionInLine, |
||||
String msg, |
||||
RecognitionException e) |
||||
{ |
||||
for (ANTLRErrorListener listener : delegates) { |
||||
listener.syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void reportAmbiguity(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
boolean exact, |
||||
BitSet ambigAlts, |
||||
ATNConfigSet configs) |
||||
{ |
||||
for (ANTLRErrorListener listener : delegates) { |
||||
listener.reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void reportAttemptingFullContext(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
BitSet conflictingAlts, |
||||
ATNConfigSet configs) |
||||
{ |
||||
for (ANTLRErrorListener listener : delegates) { |
||||
listener.reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void reportContextSensitivity(Parser recognizer, |
||||
DFA dfa, |
||||
int startIndex, |
||||
int stopIndex, |
||||
int prediction, |
||||
ATNConfigSet configs) |
||||
{ |
||||
for (ANTLRErrorListener listener : delegates) { |
||||
listener.reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs); |
||||
} |
||||
} |
||||
} |
@ -1,137 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.DecisionState; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntervalSet; |
||||
|
||||
/** The root of the ANTLR exception hierarchy. In general, ANTLR tracks just |
||||
* 3 kinds of errors: prediction errors, failed predicate errors, and |
||||
* mismatched input errors. In each case, the parser knows where it is |
||||
* in the input, where it is in the ATN, the rule invocation stack, |
||||
* and what kind of problem occurred. |
||||
*/ |
||||
public class RecognitionException extends RuntimeException { |
||||
/** The {@link Recognizer} where this exception originated. */ |
||||
private final Recognizer<?, ?> recognizer; |
||||
|
||||
private final RuleContext ctx; |
||||
|
||||
private final IntStream input; |
||||
|
||||
/** |
||||
* The current {@link Token} when an error occurred. Since not all streams |
||||
* support accessing symbols by index, we have to track the {@link Token} |
||||
* instance itself. |
||||
*/ |
||||
private Token offendingToken; |
||||
|
||||
private int offendingState = -1; |
||||
|
||||
public RecognitionException(Recognizer<?, ?> recognizer, |
||||
IntStream input, |
||||
ParserRuleContext ctx) |
||||
{ |
||||
this.recognizer = recognizer; |
||||
this.input = input; |
||||
this.ctx = ctx; |
||||
if ( recognizer!=null ) this.offendingState = recognizer.getState(); |
||||
} |
||||
|
||||
public RecognitionException(String message, |
||||
Recognizer<?, ?> recognizer, |
||||
IntStream input, |
||||
ParserRuleContext ctx) |
||||
{ |
||||
super(message); |
||||
this.recognizer = recognizer; |
||||
this.input = input; |
||||
this.ctx = ctx; |
||||
if ( recognizer!=null ) this.offendingState = recognizer.getState(); |
||||
} |
||||
|
||||
/** |
||||
* Get the ATN state number the parser was in at the time the error |
||||
* occurred. For {@link NoViableAltException} and |
||||
* {@link LexerNoViableAltException} exceptions, this is the |
||||
* {@link DecisionState} number. For others, it is the state whose outgoing |
||||
* edge we couldn't match. |
||||
* |
||||
* <p>If the state number is not known, this method returns -1.</p> |
||||
*/ |
||||
public int getOffendingState() { |
||||
return offendingState; |
||||
} |
||||
|
||||
protected final void setOffendingState(int offendingState) { |
||||
this.offendingState = offendingState; |
||||
} |
||||
|
||||
/** |
||||
* Gets the set of input symbols which could potentially follow the |
||||
* previously matched symbol at the time this exception was thrown. |
||||
* |
||||
* <p>If the set of expected tokens is not known and could not be computed, |
||||
* this method returns {@code null}.</p> |
||||
* |
||||
* @return The set of token types that could potentially follow the current |
||||
* state in the ATN, or {@code null} if the information is not available. |
||||
*/ |
||||
public IntervalSet getExpectedTokens() { |
||||
if (recognizer != null) { |
||||
return recognizer.getATN().getExpectedTokens(offendingState, ctx); |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Gets the {@link RuleContext} at the time this exception was thrown. |
||||
* |
||||
* <p>If the context is not available, this method returns {@code null}.</p> |
||||
* |
||||
* @return The {@link RuleContext} at the time this exception was thrown. |
||||
* If the context is not available, this method returns {@code null}. |
||||
*/ |
||||
public RuleContext getCtx() { |
||||
return ctx; |
||||
} |
||||
|
||||
/** |
||||
* Gets the input stream which is the symbol source for the recognizer where |
||||
* this exception was thrown. |
||||
* |
||||
* <p>If the input stream is not available, this method returns {@code null}.</p> |
||||
* |
||||
* @return The input stream which is the symbol source for the recognizer |
||||
* where this exception was thrown, or {@code null} if the stream is not |
||||
* available. |
||||
*/ |
||||
public IntStream getInputStream() { |
||||
return input; |
||||
} |
||||
|
||||
|
||||
public Token getOffendingToken() { |
||||
return offendingToken; |
||||
} |
||||
|
||||
protected final void setOffendingToken(Token offendingToken) { |
||||
this.offendingToken = offendingToken; |
||||
} |
||||
|
||||
/** |
||||
* Gets the {@link Recognizer} where this exception occurred. |
||||
* |
||||
* <p>If the recognizer is not available, this method returns {@code null}.</p> |
||||
* |
||||
* @return The recognizer where this exception occurred, or {@code null} if |
||||
* the recognizer is not available. |
||||
*/ |
||||
public Recognizer<?, ?> getRecognizer() { |
||||
return recognizer; |
||||
} |
||||
} |
@ -1,276 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATN; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATNSimulator; |
||||
import com.fr.third.org.antlr.v4.runtime.atn.ParseInfo; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Utils; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.WeakHashMap; |
||||
import java.util.concurrent.CopyOnWriteArrayList; |
||||
|
||||
public abstract class Recognizer<Symbol, ATNInterpreter extends ATNSimulator> { |
||||
public static final int EOF=-1; |
||||
|
||||
private static final Map<Vocabulary, Map<String, Integer>> tokenTypeMapCache = |
||||
new WeakHashMap<Vocabulary, Map<String, Integer>>(); |
||||
private static final Map<String[], Map<String, Integer>> ruleIndexMapCache = |
||||
new WeakHashMap<String[], Map<String, Integer>>(); |
||||
|
||||
|
||||
private List<ANTLRErrorListener> _listeners = |
||||
new CopyOnWriteArrayList<ANTLRErrorListener>() {{ |
||||
add(ConsoleErrorListener.INSTANCE); |
||||
}}; |
||||
|
||||
protected ATNInterpreter _interp; |
||||
|
||||
private int _stateNumber = -1; |
||||
|
||||
/** Used to print out token names like ID during debugging and |
||||
* error reporting. The generated parsers implement a method |
||||
* that overrides this to point to their String[] tokenNames. |
||||
* |
||||
* @deprecated Use {@link #getVocabulary()} instead. |
||||
*/ |
||||
@Deprecated |
||||
public abstract String[] getTokenNames(); |
||||
|
||||
public abstract String[] getRuleNames(); |
||||
|
||||
/** |
||||
* Get the vocabulary used by the recognizer. |
||||
* |
||||
* @return A {@link Vocabulary} instance providing information about the |
||||
* vocabulary used by the grammar. |
||||
*/ |
||||
@SuppressWarnings("deprecation") |
||||
public Vocabulary getVocabulary() { |
||||
return VocabularyImpl.fromTokenNames(getTokenNames()); |
||||
} |
||||
|
||||
/** |
||||
* Get a map from token names to token types. |
||||
* |
||||
* <p>Used for XPath and tree pattern compilation.</p> |
||||
*/ |
||||
public Map<String, Integer> getTokenTypeMap() { |
||||
Vocabulary vocabulary = getVocabulary(); |
||||
synchronized (tokenTypeMapCache) { |
||||
Map<String, Integer> result = tokenTypeMapCache.get(vocabulary); |
||||
if (result == null) { |
||||
result = new HashMap<String, Integer>(); |
||||
for (int i = 0; i <= getATN().maxTokenType; i++) { |
||||
String literalName = vocabulary.getLiteralName(i); |
||||
if (literalName != null) { |
||||
result.put(literalName, i); |
||||
} |
||||
|
||||
String symbolicName = vocabulary.getSymbolicName(i); |
||||
if (symbolicName != null) { |
||||
result.put(symbolicName, i); |
||||
} |
||||
} |
||||
|
||||
result.put("EOF", Token.EOF); |
||||
result = Collections.unmodifiableMap(result); |
||||
tokenTypeMapCache.put(vocabulary, result); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Get a map from rule names to rule indexes. |
||||
* |
||||
* <p>Used for XPath and tree pattern compilation.</p> |
||||
*/ |
||||
public Map<String, Integer> getRuleIndexMap() { |
||||
String[] ruleNames = getRuleNames(); |
||||
if (ruleNames == null) { |
||||
throw new UnsupportedOperationException("The current recognizer does not provide a list of rule names."); |
||||
} |
||||
|
||||
synchronized (ruleIndexMapCache) { |
||||
Map<String, Integer> result = ruleIndexMapCache.get(ruleNames); |
||||
if (result == null) { |
||||
result = Collections.unmodifiableMap(Utils.toMap(ruleNames)); |
||||
ruleIndexMapCache.put(ruleNames, result); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
} |
||||
|
||||
public int getTokenType(String tokenName) { |
||||
Integer ttype = getTokenTypeMap().get(tokenName); |
||||
if ( ttype!=null ) return ttype; |
||||
return Token.INVALID_TYPE; |
||||
} |
||||
|
||||
/** |
||||
* If this recognizer was generated, it will have a serialized ATN |
||||
* representation of the grammar. |
||||
* |
||||
* <p>For interpreters, we don't know their serialized ATN despite having |
||||
* created the interpreter from it.</p> |
||||
*/ |
||||
public String getSerializedATN() { |
||||
throw new UnsupportedOperationException("there is no serialized ATN"); |
||||
} |
||||
|
||||
/** For debugging and other purposes, might want the grammar name. |
||||
* Have ANTLR generate an implementation for this method. |
||||
*/ |
||||
public abstract String getGrammarFileName(); |
||||
|
||||
/** |
||||
* Get the {@link ATN} used by the recognizer for prediction. |
||||
* |
||||
* @return The {@link ATN} used by the recognizer for prediction. |
||||
*/ |
||||
public abstract ATN getATN(); |
||||
|
||||
/** |
||||
* Get the ATN interpreter used by the recognizer for prediction. |
||||
* |
||||
* @return The ATN interpreter used by the recognizer for prediction. |
||||
*/ |
||||
public ATNInterpreter getInterpreter() { |
||||
return _interp; |
||||
} |
||||
|
||||
/** If profiling during the parse/lex, this will return DecisionInfo records |
||||
* for each decision in recognizer in a ParseInfo object. |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public ParseInfo getParseInfo() { |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Set the ATN interpreter used by the recognizer for prediction. |
||||
* |
||||
* @param interpreter The ATN interpreter used by the recognizer for |
||||
* prediction. |
||||
*/ |
||||
public void setInterpreter(ATNInterpreter interpreter) { |
||||
_interp = interpreter; |
||||
} |
||||
|
||||
/** What is the error header, normally line/character position information? */ |
||||
public String getErrorHeader(RecognitionException e) { |
||||
int line = e.getOffendingToken().getLine(); |
||||
int charPositionInLine = e.getOffendingToken().getCharPositionInLine(); |
||||
return "line "+line+":"+charPositionInLine; |
||||
} |
||||
|
||||
/** How should a token be displayed in an error message? The default |
||||
* is to display just the text, but during development you might |
||||
* want to have a lot of information spit out. Override in that case |
||||
* to use t.toString() (which, for CommonToken, dumps everything about |
||||
* the token). This is better than forcing you to override a method in |
||||
* your token objects because you don't have to go modify your lexer |
||||
* so that it creates a new Java type. |
||||
* |
||||
* @deprecated This method is not called by the ANTLR 4 Runtime. Specific |
||||
* implementations of {@link ANTLRErrorStrategy} may provide a similar |
||||
* feature when necessary. For example, see |
||||
* {@link DefaultErrorStrategy#getTokenErrorDisplay}. |
||||
*/ |
||||
@Deprecated |
||||
public String getTokenErrorDisplay(Token t) { |
||||
if ( t==null ) return "<no token>"; |
||||
String s = t.getText(); |
||||
if ( s==null ) { |
||||
if ( t.getType()==Token.EOF ) { |
||||
s = "<EOF>"; |
||||
} |
||||
else { |
||||
s = "<"+t.getType()+">"; |
||||
} |
||||
} |
||||
s = s.replace("\n","\\n"); |
||||
s = s.replace("\r","\\r"); |
||||
s = s.replace("\t","\\t"); |
||||
return "'"+s+"'"; |
||||
} |
||||
|
||||
/** |
||||
* @exception NullPointerException if {@code listener} is {@code null}. |
||||
*/ |
||||
public void addErrorListener(ANTLRErrorListener listener) { |
||||
if (listener == null) { |
||||
throw new NullPointerException("listener cannot be null."); |
||||
} |
||||
|
||||
_listeners.add(listener); |
||||
} |
||||
|
||||
public void removeErrorListener(ANTLRErrorListener listener) { |
||||
_listeners.remove(listener); |
||||
} |
||||
|
||||
public void removeErrorListeners() { |
||||
_listeners.clear(); |
||||
} |
||||
|
||||
|
||||
public List<? extends ANTLRErrorListener> getErrorListeners() { |
||||
return _listeners; |
||||
} |
||||
|
||||
public ANTLRErrorListener getErrorListenerDispatch() { |
||||
return new ProxyErrorListener(getErrorListeners()); |
||||
} |
||||
|
||||
// subclass needs to override these if there are sempreds or actions
|
||||
// that the ATN interp needs to execute
|
||||
public boolean sempred(RuleContext _localctx, int ruleIndex, int actionIndex) { |
||||
return true; |
||||
} |
||||
|
||||
public boolean precpred(RuleContext localctx, int precedence) { |
||||
return true; |
||||
} |
||||
|
||||
public void action(RuleContext _localctx, int ruleIndex, int actionIndex) { |
||||
} |
||||
|
||||
public final int getState() { |
||||
return _stateNumber; |
||||
} |
||||
|
||||
/** Indicate that the recognizer has changed internal state that is |
||||
* consistent with the ATN state passed in. This way we always know |
||||
* where we are in the ATN as the parser goes along. The rule |
||||
* context objects form a stack that lets us see the stack of |
||||
* invoking rules. Combine this and we have complete ATN |
||||
* configuration information. |
||||
*/ |
||||
public final void setState(int atnState) { |
||||
// System.err.println("setState "+atnState);
|
||||
_stateNumber = atnState; |
||||
// if ( traceATNStates ) _ctx.trace(atnState);
|
||||
} |
||||
|
||||
public abstract IntStream getInputStream(); |
||||
|
||||
public abstract void setInputStream(IntStream input); |
||||
|
||||
|
||||
public abstract TokenFactory<?> getTokenFactory(); |
||||
|
||||
public abstract void setTokenFactory(TokenFactory<?> input); |
||||
} |
@ -1,252 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATN; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.ParseTree; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.ParseTreeVisitor; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.RuleNode; |
||||
import com.fr.third.org.antlr.v4.runtime.tree.Trees; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
|
||||
/** A rule context is a record of a single rule invocation. |
||||
* |
||||
* We form a stack of these context objects using the parent |
||||
* pointer. A parent pointer of null indicates that the current |
||||
* context is the bottom of the stack. The ParserRuleContext subclass |
||||
* as a children list so that we can turn this data structure into a |
||||
* tree. |
||||
* |
||||
* The root node always has a null pointer and invokingState of -1. |
||||
* |
||||
* Upon entry to parsing, the first invoked rule function creates a |
||||
* context object (a subclass specialized for that rule such as |
||||
* SContext) and makes it the root of a parse tree, recorded by field |
||||
* Parser._ctx. |
||||
* |
||||
* public final SContext s() throws RecognitionException { |
||||
* SContext _localctx = new SContext(_ctx, getState()); <-- create new node |
||||
* enterRule(_localctx, 0, RULE_s); <-- push it |
||||
* ... |
||||
* exitRule(); <-- pop back to _localctx |
||||
* return _localctx; |
||||
* } |
||||
* |
||||
* A subsequent rule invocation of r from the start rule s pushes a |
||||
* new context object for r whose parent points at s and use invoking |
||||
* state is the state with r emanating as edge label. |
||||
* |
||||
* The invokingState fields from a context object to the root |
||||
* together form a stack of rule indication states where the root |
||||
* (bottom of the stack) has a -1 sentinel value. If we invoke start |
||||
* symbol s then call r1, which calls r2, the would look like |
||||
* this: |
||||
* |
||||
* SContext[-1] <- root node (bottom of the stack) |
||||
* R1Context[p] <- p in rule s called r1 |
||||
* R2Context[q] <- q in rule r1 called r2 |
||||
* |
||||
* So the top of the stack, _ctx, represents a call to the current |
||||
* rule and it holds the return address from another rule that invoke |
||||
* to this rule. To invoke a rule, we must always have a current context. |
||||
* |
||||
* The parent contexts are useful for computing lookahead sets and |
||||
* getting error information. |
||||
* |
||||
* These objects are used during parsing and prediction. |
||||
* For the special case of parsers, we use the subclass |
||||
* ParserRuleContext. |
||||
* |
||||
* @see ParserRuleContext |
||||
*/ |
||||
public class RuleContext implements RuleNode { |
||||
public static final ParserRuleContext EMPTY = new ParserRuleContext(); |
||||
|
||||
/** What context invoked this rule? */ |
||||
public RuleContext parent; |
||||
|
||||
/** What state invoked the rule associated with this context? |
||||
* The "return address" is the followState of invokingState |
||||
* If parent is null, this should be -1 this context object represents |
||||
* the start rule. |
||||
*/ |
||||
public int invokingState = -1; |
||||
|
||||
public RuleContext() {} |
||||
|
||||
public RuleContext(RuleContext parent, int invokingState) { |
||||
this.parent = parent; |
||||
//if ( parent!=null ) System.out.println("invoke "+stateNumber+" from "+parent);
|
||||
this.invokingState = invokingState; |
||||
} |
||||
|
||||
public int depth() { |
||||
int n = 0; |
||||
RuleContext p = this; |
||||
while ( p!=null ) { |
||||
p = p.parent; |
||||
n++; |
||||
} |
||||
return n; |
||||
} |
||||
|
||||
/** A context is empty if there is no invoking state; meaning nobody called |
||||
* current context. |
||||
*/ |
||||
public boolean isEmpty() { |
||||
return invokingState == -1; |
||||
} |
||||
|
||||
// satisfy the ParseTree / SyntaxTree interface
|
||||
|
||||
@Override |
||||
public Interval getSourceInterval() { |
||||
return Interval.INVALID; |
||||
} |
||||
|
||||
@Override |
||||
public RuleContext getRuleContext() { return this; } |
||||
|
||||
@Override |
||||
public RuleContext getParent() { return parent; } |
||||
|
||||
@Override |
||||
public RuleContext getPayload() { return this; } |
||||
|
||||
/** Return the combined text of all child nodes. This method only considers |
||||
* tokens which have been added to the parse tree. |
||||
* <p> |
||||
* Since tokens on hidden channels (e.g. whitespace or comments) are not |
||||
* added to the parse trees, they will not appear in the output of this |
||||
* method. |
||||
*/ |
||||
@Override |
||||
public String getText() { |
||||
if (getChildCount() == 0) { |
||||
return ""; |
||||
} |
||||
|
||||
StringBuilder builder = new StringBuilder(); |
||||
for (int i = 0; i < getChildCount(); i++) { |
||||
builder.append(getChild(i).getText()); |
||||
} |
||||
|
||||
return builder.toString(); |
||||
} |
||||
|
||||
public int getRuleIndex() { return -1; } |
||||
|
||||
/** For rule associated with this parse tree internal node, return |
||||
* the outer alternative number used to match the input. Default |
||||
* implementation does not compute nor store this alt num. Create |
||||
* a subclass of ParserRuleContext with backing field and set |
||||
* option contextSuperClass. |
||||
* to set it. |
||||
* |
||||
* @since 4.5.3 |
||||
*/ |
||||
public int getAltNumber() { return ATN.INVALID_ALT_NUMBER; } |
||||
|
||||
/** Set the outer alternative number for this context node. Default |
||||
* implementation does nothing to avoid backing field overhead for |
||||
* trees that don't need it. Create |
||||
* a subclass of ParserRuleContext with backing field and set |
||||
* option contextSuperClass. |
||||
* |
||||
* @since 4.5.3 |
||||
*/ |
||||
public void setAltNumber(int altNumber) { } |
||||
|
||||
/** @since 4.7. {@see ParseTree#setParent} comment */ |
||||
@Override |
||||
public void setParent(RuleContext parent) { |
||||
this.parent = parent; |
||||
} |
||||
|
||||
@Override |
||||
public ParseTree getChild(int i) { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public int getChildCount() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public <T> T accept(ParseTreeVisitor<? extends T> visitor) { return visitor.visitChildren(this); } |
||||
|
||||
/** Print out a whole tree, not just a node, in LISP format |
||||
* (root child1 .. childN). Print just a node if this is a leaf. |
||||
* We have to know the recognizer so we can get rule names. |
||||
*/ |
||||
@Override |
||||
public String toStringTree(Parser recog) { |
||||
return Trees.toStringTree(this, recog); |
||||
} |
||||
|
||||
/** Print out a whole tree, not just a node, in LISP format |
||||
* (root child1 .. childN). Print just a node if this is a leaf. |
||||
*/ |
||||
public String toStringTree(List<String> ruleNames) { |
||||
return Trees.toStringTree(this, ruleNames); |
||||
} |
||||
|
||||
@Override |
||||
public String toStringTree() { |
||||
return toStringTree((List<String>)null); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return toString((List<String>)null, (RuleContext)null); |
||||
} |
||||
|
||||
public final String toString(Recognizer<?,?> recog) { |
||||
return toString(recog, ParserRuleContext.EMPTY); |
||||
} |
||||
|
||||
public final String toString(List<String> ruleNames) { |
||||
return toString(ruleNames, null); |
||||
} |
||||
|
||||
// recog null unless ParserRuleContext, in which case we use subclass toString(...)
|
||||
public String toString(Recognizer<?,?> recog, RuleContext stop) { |
||||
String[] ruleNames = recog != null ? recog.getRuleNames() : null; |
||||
List<String> ruleNamesList = ruleNames != null ? Arrays.asList(ruleNames) : null; |
||||
return toString(ruleNamesList, stop); |
||||
} |
||||
|
||||
public String toString(List<String> ruleNames, RuleContext stop) { |
||||
StringBuilder buf = new StringBuilder(); |
||||
RuleContext p = this; |
||||
buf.append("["); |
||||
while (p != null && p != stop) { |
||||
if (ruleNames == null) { |
||||
if (!p.isEmpty()) { |
||||
buf.append(p.invokingState); |
||||
} |
||||
} |
||||
else { |
||||
int ruleIndex = p.getRuleIndex(); |
||||
String ruleName = ruleIndex >= 0 && ruleIndex < ruleNames.size() ? ruleNames.get(ruleIndex) : Integer.toString(ruleIndex); |
||||
buf.append(ruleName); |
||||
} |
||||
|
||||
if (p.parent != null && (ruleNames != null || !p.parent.isEmpty())) { |
||||
buf.append(" "); |
||||
} |
||||
|
||||
p = p.parent; |
||||
} |
||||
|
||||
buf.append("]"); |
||||
return buf.toString(); |
||||
} |
||||
} |
@ -1,30 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.atn.ATN; |
||||
|
||||
/** A handy class for use with |
||||
* |
||||
* options {contextSuperClass=com.fr.third.org.antlr.v4.runtime.RuleContextWithAltNum;} |
||||
* |
||||
* that provides a backing field / impl for the outer alternative number |
||||
* matched for an internal parse tree node. |
||||
* |
||||
* I'm only putting into Java runtime as I'm certain I'm the only one that |
||||
* will really every use this. |
||||
*/ |
||||
public class RuleContextWithAltNum extends ParserRuleContext { |
||||
public int altNum; |
||||
public RuleContextWithAltNum() { altNum = ATN.INVALID_ALT_NUMBER; } |
||||
|
||||
public RuleContextWithAltNum(ParserRuleContext parent, int invokingStateNumber) { |
||||
super(parent, invokingStateNumber); |
||||
} |
||||
@Override public int getAltNumber() { return altNum; } |
||||
@Override public void setAltNumber(int altNum) { this.altNum = altNum; } |
||||
} |
@ -1,193 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
/** |
||||
* This class provides access to the current version of the ANTLR 4 runtime |
||||
* library as compile-time and runtime constants, along with methods for |
||||
* checking for matching version numbers and notifying listeners in the case |
||||
* where a version mismatch is detected. |
||||
* |
||||
* <p> |
||||
* The runtime version information is provided by {@link #VERSION} and |
||||
* {@link #getRuntimeVersion()}. Detailed information about these values is |
||||
* provided in the documentation for each member.</p> |
||||
* |
||||
* <p> |
||||
* The runtime version check is implemented by {@link #checkVersion}. Detailed |
||||
* information about incorporating this call into user code, as well as its use |
||||
* in generated code, is provided in the documentation for the method.</p> |
||||
* |
||||
* <p> |
||||
* Version strings x.y and x.y.z are considered "compatible" and no error |
||||
* would be generated. Likewise, version strings x.y-SNAPSHOT and x.y.z are |
||||
* considered "compatible" because the major and minor components x.y |
||||
* are the same in each.</p> |
||||
* |
||||
* <p> |
||||
* To trap any error messages issued by this code, use System.setErr() |
||||
* in your main() startup code. |
||||
* </p> |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public class RuntimeMetaData { |
||||
/** |
||||
* A compile-time constant containing the current version of the ANTLR 4 |
||||
* runtime library. |
||||
* |
||||
* <p> |
||||
* This compile-time constant value allows generated parsers and other |
||||
* libraries to include a literal reference to the version of the ANTLR 4 |
||||
* runtime library the code was compiled against. At each release, we |
||||
* change this value.</p> |
||||
* |
||||
* <p>Version numbers are assumed to have the form |
||||
* |
||||
* <em>major</em>.<em>minor</em>.<em>patch</em>.<em>revision</em>-<em>suffix</em>, |
||||
* |
||||
* with the individual components defined as follows.</p> |
||||
* |
||||
* <ul> |
||||
* <li><em>major</em> is a required non-negative integer, and is equal to |
||||
* {@code 4} for ANTLR 4.</li> |
||||
* <li><em>minor</em> is a required non-negative integer.</li> |
||||
* <li><em>patch</em> is an optional non-negative integer. When |
||||
* <em>patch</em> is omitted, the {@code .} (dot) appearing before it is |
||||
* also omitted.</li> |
||||
* <li><em>revision</em> is an optional non-negative integer, and may only |
||||
* be included when <em>patch</em> is also included. When <em>revision</em> |
||||
* is omitted, the {@code .} (dot) appearing before it is also omitted.</li> |
||||
* <li><em>suffix</em> is an optional string. When <em>suffix</em> is |
||||
* omitted, the {@code -} (hyphen-minus) appearing before it is also |
||||
* omitted.</li> |
||||
* </ul> |
||||
*/ |
||||
public static final String VERSION = "4.7.2"; |
||||
|
||||
/** |
||||
* Gets the currently executing version of the ANTLR 4 runtime library. |
||||
* |
||||
* <p> |
||||
* This method provides runtime access to the {@link #VERSION} field, as |
||||
* opposed to directly referencing the field as a compile-time constant.</p> |
||||
* |
||||
* @return The currently executing version of the ANTLR 4 library |
||||
*/ |
||||
|
||||
public static String getRuntimeVersion() { |
||||
return VERSION; |
||||
} |
||||
|
||||
/** |
||||
* This method provides the ability to detect mismatches between the version |
||||
* of ANTLR 4 used to generate a parser, the version of the ANTLR runtime a |
||||
* parser was compiled against, and the version of the ANTLR runtime which |
||||
* is currently executing. |
||||
* |
||||
* <p> |
||||
* The version check is designed to detect the following two specific |
||||
* scenarios.</p> |
||||
* |
||||
* <ul> |
||||
* <li>The ANTLR Tool version used for code generation does not match the |
||||
* currently executing runtime version.</li> |
||||
* <li>The ANTLR Runtime version referenced at the time a parser was |
||||
* compiled does not match the currently executing runtime version.</li> |
||||
* </ul> |
||||
* |
||||
* <p> |
||||
* Starting with ANTLR 4.3, the code generator emits a call to this method |
||||
* using two constants in each generated lexer and parser: a hard-coded |
||||
* constant indicating the version of the tool used to generate the parser |
||||
* and a reference to the compile-time constant {@link #VERSION}. At |
||||
* runtime, this method is called during the initialization of the generated |
||||
* parser to detect mismatched versions, and notify the registered listeners |
||||
* prior to creating instances of the parser.</p> |
||||
* |
||||
* <p> |
||||
* This method does not perform any detection or filtering of semantic |
||||
* changes between tool and runtime versions. It simply checks for a |
||||
* version match and emits an error to stderr if a difference |
||||
* is detected.</p> |
||||
* |
||||
* <p> |
||||
* Note that some breaking changes between releases could result in other |
||||
* types of runtime exceptions, such as a {@link LinkageError}, prior to |
||||
* calling this method. In these cases, the underlying version mismatch will |
||||
* not be reported here. This method is primarily intended to |
||||
* notify users of potential semantic changes between releases that do not |
||||
* result in binary compatibility problems which would be detected by the |
||||
* class loader. As with semantic changes, changes that break binary |
||||
* compatibility between releases are mentioned in the release notes |
||||
* accompanying the affected release.</p> |
||||
* |
||||
* <p> |
||||
* <strong>Additional note for target developers:</strong> The version check |
||||
* implemented by this class is designed to address specific compatibility |
||||
* concerns that may arise during the execution of Java applications. Other |
||||
* targets should consider the implementation of this method in the context |
||||
* of that target's known execution environment, which may or may not |
||||
* resemble the design provided for the Java target.</p> |
||||
* |
||||
* @param generatingToolVersion The version of the tool used to generate a parser. |
||||
* This value may be null when called from user code that was not generated |
||||
* by, and does not reference, the ANTLR 4 Tool itself. |
||||
* @param compileTimeVersion The version of the runtime the parser was |
||||
* compiled against. This should always be passed using a direct reference |
||||
* to {@link #VERSION}. |
||||
*/ |
||||
public static void checkVersion(String generatingToolVersion, String compileTimeVersion) { |
||||
String runtimeVersion = VERSION; |
||||
boolean runtimeConflictsWithGeneratingTool = false; |
||||
boolean runtimeConflictsWithCompileTimeTool = false; |
||||
|
||||
if ( generatingToolVersion!=null ) { |
||||
runtimeConflictsWithGeneratingTool = |
||||
!runtimeVersion.equals(generatingToolVersion) && |
||||
!getMajorMinorVersion(runtimeVersion).equals(getMajorMinorVersion(generatingToolVersion)); |
||||
} |
||||
|
||||
runtimeConflictsWithCompileTimeTool = |
||||
!runtimeVersion.equals(compileTimeVersion) && |
||||
!getMajorMinorVersion(runtimeVersion).equals(getMajorMinorVersion(compileTimeVersion)); |
||||
|
||||
if ( runtimeConflictsWithGeneratingTool ) { |
||||
System.err.printf("ANTLR Tool version %s used for code generation does not match the current runtime version %s", |
||||
generatingToolVersion, runtimeVersion); |
||||
} |
||||
if ( runtimeConflictsWithCompileTimeTool ) { |
||||
System.err.printf("ANTLR Runtime version %s used for parser compilation does not match the current runtime version %s", |
||||
compileTimeVersion, runtimeVersion); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets the major and minor version numbers from a version string. For |
||||
* details about the syntax of the input {@code version}. |
||||
* E.g., from x.y.z return x.y. |
||||
* |
||||
* @param version The complete version string. |
||||
* @return A string of the form <em>major</em>.<em>minor</em> containing |
||||
* only the major and minor components of the version string. |
||||
*/ |
||||
public static String getMajorMinorVersion(String version) { |
||||
int firstDot = version.indexOf('.'); |
||||
int secondDot = firstDot >= 0 ? version.indexOf('.', firstDot + 1) : -1; |
||||
int firstDash = version.indexOf('-'); |
||||
int referenceLength = version.length(); |
||||
if (secondDot >= 0) { |
||||
referenceLength = Math.min(referenceLength, secondDot); |
||||
} |
||||
|
||||
if (firstDash >= 0) { |
||||
referenceLength = Math.min(referenceLength, firstDash); |
||||
} |
||||
|
||||
return version.substring(0, referenceLength); |
||||
} |
||||
} |
@ -1,100 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
/** A token has properties: text, type, line, character position in the line |
||||
* (so we can ignore tabs), token channel, index, and source from which |
||||
* we obtained this token. |
||||
*/ |
||||
public interface Token { |
||||
public static final int INVALID_TYPE = 0; |
||||
|
||||
/** During lookahead operations, this "token" signifies we hit rule end ATN state |
||||
* and did not follow it despite needing to. |
||||
*/ |
||||
public static final int EPSILON = -2; |
||||
|
||||
public static final int MIN_USER_TOKEN_TYPE = 1; |
||||
|
||||
public static final int EOF = IntStream.EOF; |
||||
|
||||
/** All tokens go to the parser (unless skip() is called in that rule) |
||||
* on a particular "channel". The parser tunes to a particular channel |
||||
* so that whitespace etc... can go to the parser on a "hidden" channel. |
||||
*/ |
||||
public static final int DEFAULT_CHANNEL = 0; |
||||
|
||||
/** Anything on different channel than DEFAULT_CHANNEL is not parsed |
||||
* by parser. |
||||
*/ |
||||
public static final int HIDDEN_CHANNEL = 1; |
||||
|
||||
/** |
||||
* This is the minimum constant value which can be assigned to a |
||||
* user-defined token channel. |
||||
* |
||||
* <p> |
||||
* The non-negative numbers less than {@link #MIN_USER_CHANNEL_VALUE} are |
||||
* assigned to the predefined channels {@link #DEFAULT_CHANNEL} and |
||||
* {@link #HIDDEN_CHANNEL}.</p> |
||||
* |
||||
* @see Token#getChannel() |
||||
*/ |
||||
public static final int MIN_USER_CHANNEL_VALUE = 2; |
||||
|
||||
/** |
||||
* Get the text of the token. |
||||
*/ |
||||
String getText(); |
||||
|
||||
/** Get the token type of the token */ |
||||
int getType(); |
||||
|
||||
/** The line number on which the 1st character of this token was matched, |
||||
* line=1..n |
||||
*/ |
||||
int getLine(); |
||||
|
||||
/** The index of the first character of this token relative to the |
||||
* beginning of the line at which it occurs, 0..n-1 |
||||
*/ |
||||
int getCharPositionInLine(); |
||||
|
||||
/** Return the channel this token. Each token can arrive at the parser |
||||
* on a different channel, but the parser only "tunes" to a single channel. |
||||
* The parser ignores everything not on DEFAULT_CHANNEL. |
||||
*/ |
||||
int getChannel(); |
||||
|
||||
/** An index from 0..n-1 of the token object in the input stream. |
||||
* This must be valid in order to print token streams and |
||||
* use TokenRewriteStream. |
||||
* |
||||
* Return -1 to indicate that this token was conjured up since |
||||
* it doesn't have a valid index. |
||||
*/ |
||||
int getTokenIndex(); |
||||
|
||||
/** The starting character index of the token |
||||
* This method is optional; return -1 if not implemented. |
||||
*/ |
||||
int getStartIndex(); |
||||
|
||||
/** The last character index of the token. |
||||
* This method is optional; return -1 if not implemented. |
||||
*/ |
||||
int getStopIndex(); |
||||
|
||||
/** Gets the {@link TokenSource} which created this token. |
||||
*/ |
||||
TokenSource getTokenSource(); |
||||
|
||||
/** |
||||
* Gets the {@link CharStream} from which this token was derived. |
||||
*/ |
||||
CharStream getInputStream(); |
||||
} |
@ -1,26 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Pair; |
||||
|
||||
/** The default mechanism for creating tokens. It's used by default in Lexer and |
||||
* the error handling strategy (to create missing tokens). Notifying the parser |
||||
* of a new factory means that it notifies its token source and error strategy. |
||||
*/ |
||||
public interface TokenFactory<Symbol extends Token> { |
||||
/** This is the method used to create tokens in the lexer and in the |
||||
* error handling strategy. If text!=null, than the start and stop positions |
||||
* are wiped to -1 in the text override is set in the CommonToken. |
||||
*/ |
||||
Symbol create(Pair<TokenSource, CharStream> source, int type, String text, |
||||
int channel, int start, int stop, |
||||
int line, int charPositionInLine); |
||||
|
||||
/** Generically useful */ |
||||
Symbol create(int type, String text); |
||||
} |
@ -1,82 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
/** |
||||
* A source of tokens must provide a sequence of tokens via {@link #nextToken()} |
||||
* and also must reveal it's source of characters; {@link CommonToken}'s text is |
||||
* computed from a {@link CharStream}; it only store indices into the char |
||||
* stream. |
||||
* |
||||
* <p>Errors from the lexer are never passed to the parser. Either you want to keep |
||||
* going or you do not upon token recognition error. If you do not want to |
||||
* continue lexing then you do not want to continue parsing. Just throw an |
||||
* exception not under {@link RecognitionException} and Java will naturally toss |
||||
* you all the way out of the recognizers. If you want to continue lexing then |
||||
* you should not throw an exception to the parser--it has already requested a |
||||
* token. Keep lexing until you get a valid one. Just report errors and keep |
||||
* going, looking for a valid token.</p> |
||||
*/ |
||||
public interface TokenSource { |
||||
/** |
||||
* Return a {@link Token} object from your input stream (usually a |
||||
* {@link CharStream}). Do not fail/return upon lexing error; keep chewing |
||||
* on the characters until you get a good one; errors are not passed through |
||||
* to the parser. |
||||
*/ |
||||
public Token nextToken(); |
||||
|
||||
/** |
||||
* Get the line number for the current position in the input stream. The |
||||
* first line in the input is line 1. |
||||
* |
||||
* @return The line number for the current position in the input stream, or |
||||
* 0 if the current token source does not track line numbers. |
||||
*/ |
||||
public int getLine(); |
||||
|
||||
/** |
||||
* Get the index into the current line for the current position in the input |
||||
* stream. The first character on a line has position 0. |
||||
* |
||||
* @return The line number for the current position in the input stream, or |
||||
* -1 if the current token source does not track character positions. |
||||
*/ |
||||
public int getCharPositionInLine(); |
||||
|
||||
/** |
||||
* Get the {@link CharStream} from which this token source is currently |
||||
* providing tokens. |
||||
* |
||||
* @return The {@link CharStream} associated with the current position in |
||||
* the input, or {@code null} if no input stream is available for the token |
||||
* source. |
||||
*/ |
||||
public CharStream getInputStream(); |
||||
|
||||
/** |
||||
* Gets the name of the underlying input source. This method returns a |
||||
* non-null, non-empty string. If such a name is not known, this method |
||||
* returns {@link IntStream#UNKNOWN_SOURCE_NAME}. |
||||
*/ |
||||
public String getSourceName(); |
||||
|
||||
/** |
||||
* Set the {@link TokenFactory} this token source should use for creating |
||||
* {@link Token} objects from the input. |
||||
* |
||||
* @param factory The {@link TokenFactory} to use for creating tokens. |
||||
*/ |
||||
public void setTokenFactory(TokenFactory<?> factory); |
||||
|
||||
/** |
||||
* Gets the {@link TokenFactory} this token source is currently using for |
||||
* creating {@link Token} objects from the input. |
||||
* |
||||
* @return The {@link TokenFactory} currently used by this token source. |
||||
*/ |
||||
public TokenFactory<?> getTokenFactory(); |
||||
} |
@ -1,140 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
|
||||
/** |
||||
* An {@link IntStream} whose symbols are {@link Token} instances. |
||||
*/ |
||||
public interface TokenStream extends IntStream { |
||||
/** |
||||
* Get the {@link Token} instance associated with the value returned by |
||||
* {@link #LA LA(k)}. This method has the same pre- and post-conditions as |
||||
* {@link IntStream#LA}. In addition, when the preconditions of this method |
||||
* are met, the return value is non-null and the value of |
||||
* {@code LT(k).getType()==LA(k)}. |
||||
* |
||||
* @see IntStream#LA |
||||
*/ |
||||
public Token LT(int k); |
||||
|
||||
/** |
||||
* Gets the {@link Token} at the specified {@code index} in the stream. When |
||||
* the preconditions of this method are met, the return value is non-null. |
||||
* |
||||
* <p>The preconditions for this method are the same as the preconditions of |
||||
* {@link IntStream#seek}. If the behavior of {@code seek(index)} is |
||||
* unspecified for the current state and given {@code index}, then the |
||||
* behavior of this method is also unspecified.</p> |
||||
* |
||||
* <p>The symbol referred to by {@code index} differs from {@code seek()} only |
||||
* in the case of filtering streams where {@code index} lies before the end |
||||
* of the stream. Unlike {@code seek()}, this method does not adjust |
||||
* {@code index} to point to a non-ignored symbol.</p> |
||||
* |
||||
* @throws IllegalArgumentException if {code index} is less than 0 |
||||
* @throws UnsupportedOperationException if the stream does not support |
||||
* retrieving the token at the specified index |
||||
*/ |
||||
public Token get(int index); |
||||
|
||||
/** |
||||
* Gets the underlying {@link TokenSource} which provides tokens for this |
||||
* stream. |
||||
*/ |
||||
public TokenSource getTokenSource(); |
||||
|
||||
/** |
||||
* Return the text of all tokens within the specified {@code interval}. This |
||||
* method behaves like the following code (including potential exceptions |
||||
* for violating preconditions of {@link #get}, but may be optimized by the |
||||
* specific implementation. |
||||
* |
||||
* <pre> |
||||
* TokenStream stream = ...; |
||||
* String text = ""; |
||||
* for (int i = interval.a; i <= interval.b; i++) { |
||||
* text += stream.get(i).getText(); |
||||
* } |
||||
* </pre> |
||||
* |
||||
* @param interval The interval of tokens within this stream to get text |
||||
* for. |
||||
* @return The text of all tokens within the specified interval in this |
||||
* stream. |
||||
* |
||||
* @throws NullPointerException if {@code interval} is {@code null} |
||||
*/ |
||||
public String getText(Interval interval); |
||||
|
||||
/** |
||||
* Return the text of all tokens in the stream. This method behaves like the |
||||
* following code, including potential exceptions from the calls to |
||||
* {@link IntStream#size} and {@link #getText(Interval)}, but may be |
||||
* optimized by the specific implementation. |
||||
* |
||||
* <pre> |
||||
* TokenStream stream = ...; |
||||
* String text = stream.getText(new Interval(0, stream.size())); |
||||
* </pre> |
||||
* |
||||
* @return The text of all tokens in the stream. |
||||
*/ |
||||
public String getText(); |
||||
|
||||
/** |
||||
* Return the text of all tokens in the source interval of the specified |
||||
* context. This method behaves like the following code, including potential |
||||
* exceptions from the call to {@link #getText(Interval)}, but may be |
||||
* optimized by the specific implementation. |
||||
* |
||||
* <p>If {@code ctx.getSourceInterval()} does not return a valid interval of |
||||
* tokens provided by this stream, the behavior is unspecified.</p> |
||||
* |
||||
* <pre> |
||||
* TokenStream stream = ...; |
||||
* String text = stream.getText(ctx.getSourceInterval()); |
||||
* </pre> |
||||
* |
||||
* @param ctx The context providing the source interval of tokens to get |
||||
* text for. |
||||
* @return The text of all tokens within the source interval of {@code ctx}. |
||||
*/ |
||||
public String getText(RuleContext ctx); |
||||
|
||||
/** |
||||
* Return the text of all tokens in this stream between {@code start} and |
||||
* {@code stop} (inclusive). |
||||
* |
||||
* <p>If the specified {@code start} or {@code stop} token was not provided by |
||||
* this stream, or if the {@code stop} occurred before the {@code start} |
||||
* token, the behavior is unspecified.</p> |
||||
* |
||||
* <p>For streams which ensure that the {@link Token#getTokenIndex} method is |
||||
* accurate for all of its provided tokens, this method behaves like the |
||||
* following code. Other streams may implement this method in other ways |
||||
* provided the behavior is consistent with this at a high level.</p> |
||||
* |
||||
* <pre> |
||||
* TokenStream stream = ...; |
||||
* String text = ""; |
||||
* for (int i = start.getTokenIndex(); i <= stop.getTokenIndex(); i++) { |
||||
* text += stream.get(i).getText(); |
||||
* } |
||||
* </pre> |
||||
* |
||||
* @param start The first token in the interval to get text for. |
||||
* @param stop The last token in the interval to get text for (inclusive). |
||||
* @return The text of all tokens lying between the specified {@code start} |
||||
* and {@code stop} tokens. |
||||
* |
||||
* @throws UnsupportedOperationException if this stream does not support |
||||
* this method for the specified tokens |
||||
*/ |
||||
public String getText(Token start, Token stop); |
||||
} |
@ -1,597 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Useful for rewriting out a buffered input token stream after doing some |
||||
* augmentation or other manipulations on it. |
||||
* |
||||
* <p> |
||||
* You can insert stuff, replace, and delete chunks. Note that the operations |
||||
* are done lazily--only if you convert the buffer to a {@link String} with |
||||
* {@link TokenStream#getText()}. This is very efficient because you are not |
||||
* moving data around all the time. As the buffer of tokens is converted to |
||||
* strings, the {@link #getText()} method(s) scan the input token stream and |
||||
* check to see if there is an operation at the current index. If so, the |
||||
* operation is done and then normal {@link String} rendering continues on the |
||||
* buffer. This is like having multiple Turing machine instruction streams |
||||
* (programs) operating on a single input tape. :)</p> |
||||
* |
||||
* <p> |
||||
* This rewriter makes no modifications to the token stream. It does not ask the |
||||
* stream to fill itself up nor does it advance the input cursor. The token |
||||
* stream {@link TokenStream#index()} will return the same value before and |
||||
* after any {@link #getText()} call.</p> |
||||
* |
||||
* <p> |
||||
* The rewriter only works on tokens that you have in the buffer and ignores the |
||||
* current input cursor. If you are buffering tokens on-demand, calling |
||||
* {@link #getText()} halfway through the input will only do rewrites for those |
||||
* tokens in the first half of the file.</p> |
||||
* |
||||
* <p> |
||||
* Since the operations are done lazily at {@link #getText}-time, operations do |
||||
* not screw up the token index values. That is, an insert operation at token |
||||
* index {@code i} does not change the index values for tokens |
||||
* {@code i}+1..n-1.</p> |
||||
* |
||||
* <p> |
||||
* Because operations never actually alter the buffer, you may always get the |
||||
* original token stream back without undoing anything. Since the instructions |
||||
* are queued up, you can easily simulate transactions and roll back any changes |
||||
* if there is an error just by removing instructions. For example,</p> |
||||
* |
||||
* <pre> |
||||
* CharStream input = new ANTLRFileStream("input"); |
||||
* TLexer lex = new TLexer(input); |
||||
* CommonTokenStream tokens = new CommonTokenStream(lex); |
||||
* T parser = new T(tokens); |
||||
* TokenStreamRewriter rewriter = new TokenStreamRewriter(tokens); |
||||
* parser.startRule(); |
||||
* </pre> |
||||
* |
||||
* <p> |
||||
* Then in the rules, you can execute (assuming rewriter is visible):</p> |
||||
* |
||||
* <pre> |
||||
* Token t,u; |
||||
* ... |
||||
* rewriter.insertAfter(t, "text to put after t");} |
||||
* rewriter.insertAfter(u, "text after u");} |
||||
* System.out.println(rewriter.getText()); |
||||
* </pre> |
||||
* |
||||
* <p> |
||||
* You can also have multiple "instruction streams" and get multiple rewrites |
||||
* from a single pass over the input. Just name the instruction streams and use |
||||
* that name again when printing the buffer. This could be useful for generating |
||||
* a C file and also its header file--all from the same buffer:</p> |
||||
* |
||||
* <pre> |
||||
* rewriter.insertAfter("pass1", t, "text to put after t");} |
||||
* rewriter.insertAfter("pass2", u, "text after u");} |
||||
* System.out.println(rewriter.getText("pass1")); |
||||
* System.out.println(rewriter.getText("pass2")); |
||||
* </pre> |
||||
* |
||||
* <p> |
||||
* If you don't use named rewrite streams, a "default" stream is used as the |
||||
* first example shows.</p> |
||||
*/ |
||||
public class TokenStreamRewriter { |
||||
public static final String DEFAULT_PROGRAM_NAME = "default"; |
||||
public static final int PROGRAM_INIT_SIZE = 100; |
||||
public static final int MIN_TOKEN_INDEX = 0; |
||||
|
||||
// Define the rewrite operation hierarchy
|
||||
|
||||
public class RewriteOperation { |
||||
/** What index into rewrites List are we? */ |
||||
protected int instructionIndex; |
||||
/** Token buffer index. */ |
||||
protected int index; |
||||
protected Object text; |
||||
|
||||
protected RewriteOperation(int index) { |
||||
this.index = index; |
||||
} |
||||
|
||||
protected RewriteOperation(int index, Object text) { |
||||
this.index = index; |
||||
this.text = text; |
||||
} |
||||
/** Execute the rewrite operation by possibly adding to the buffer. |
||||
* Return the index of the next token to operate on. |
||||
*/ |
||||
public int execute(StringBuilder buf) { |
||||
return index; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
String opName = getClass().getName(); |
||||
int $index = opName.indexOf('$'); |
||||
opName = opName.substring($index+1, opName.length()); |
||||
return "<"+opName+"@"+tokens.get(index)+ |
||||
":\""+text+"\">"; |
||||
} |
||||
} |
||||
|
||||
class InsertBeforeOp extends RewriteOperation { |
||||
public InsertBeforeOp(int index, Object text) { |
||||
super(index,text); |
||||
} |
||||
|
||||
@Override |
||||
public int execute(StringBuilder buf) { |
||||
buf.append(text); |
||||
if ( tokens.get(index).getType()!=Token.EOF ) { |
||||
buf.append(tokens.get(index).getText()); |
||||
} |
||||
return index+1; |
||||
} |
||||
} |
||||
|
||||
/** Distinguish between insert after/before to do the "insert afters" |
||||
* first and then the "insert befores" at same index. Implementation |
||||
* of "insert after" is "insert before index+1". |
||||
*/ |
||||
class InsertAfterOp extends InsertBeforeOp { |
||||
public InsertAfterOp(int index, Object text) { |
||||
super(index+1, text); // insert after is insert before index+1
|
||||
} |
||||
} |
||||
|
||||
/** I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp |
||||
* instructions. |
||||
*/ |
||||
class ReplaceOp extends RewriteOperation { |
||||
protected int lastIndex; |
||||
public ReplaceOp(int from, int to, Object text) { |
||||
super(from,text); |
||||
lastIndex = to; |
||||
} |
||||
@Override |
||||
public int execute(StringBuilder buf) { |
||||
if ( text!=null ) { |
||||
buf.append(text); |
||||
} |
||||
return lastIndex+1; |
||||
} |
||||
@Override |
||||
public String toString() { |
||||
if ( text==null ) { |
||||
return "<DeleteOp@"+tokens.get(index)+ |
||||
".."+tokens.get(lastIndex)+">"; |
||||
} |
||||
return "<ReplaceOp@"+tokens.get(index)+ |
||||
".."+tokens.get(lastIndex)+":\""+text+"\">"; |
||||
} |
||||
} |
||||
|
||||
/** Our source stream */ |
||||
protected final TokenStream tokens; |
||||
|
||||
/** You may have multiple, named streams of rewrite operations. |
||||
* I'm calling these things "programs." |
||||
* Maps String (name) → rewrite (List) |
||||
*/ |
||||
protected final Map<String, List<RewriteOperation>> programs; |
||||
|
||||
/** Map String (program name) → Integer index */ |
||||
protected final Map<String, Integer> lastRewriteTokenIndexes; |
||||
|
||||
public TokenStreamRewriter(TokenStream tokens) { |
||||
this.tokens = tokens; |
||||
programs = new HashMap<String, List<RewriteOperation>>(); |
||||
programs.put(DEFAULT_PROGRAM_NAME, |
||||
new ArrayList<RewriteOperation>(PROGRAM_INIT_SIZE)); |
||||
lastRewriteTokenIndexes = new HashMap<String, Integer>(); |
||||
} |
||||
|
||||
public final TokenStream getTokenStream() { |
||||
return tokens; |
||||
} |
||||
|
||||
public void rollback(int instructionIndex) { |
||||
rollback(DEFAULT_PROGRAM_NAME, instructionIndex); |
||||
} |
||||
|
||||
/** Rollback the instruction stream for a program so that |
||||
* the indicated instruction (via instructionIndex) is no |
||||
* longer in the stream. UNTESTED! |
||||
*/ |
||||
public void rollback(String programName, int instructionIndex) { |
||||
List<RewriteOperation> is = programs.get(programName); |
||||
if ( is!=null ) { |
||||
programs.put(programName, is.subList(MIN_TOKEN_INDEX,instructionIndex)); |
||||
} |
||||
} |
||||
|
||||
public void deleteProgram() { |
||||
deleteProgram(DEFAULT_PROGRAM_NAME); |
||||
} |
||||
|
||||
/** Reset the program so that no instructions exist */ |
||||
public void deleteProgram(String programName) { |
||||
rollback(programName, MIN_TOKEN_INDEX); |
||||
} |
||||
|
||||
public void insertAfter(Token t, Object text) { |
||||
insertAfter(DEFAULT_PROGRAM_NAME, t, text); |
||||
} |
||||
|
||||
public void insertAfter(int index, Object text) { |
||||
insertAfter(DEFAULT_PROGRAM_NAME, index, text); |
||||
} |
||||
|
||||
public void insertAfter(String programName, Token t, Object text) { |
||||
insertAfter(programName,t.getTokenIndex(), text); |
||||
} |
||||
|
||||
public void insertAfter(String programName, int index, Object text) { |
||||
// to insert after, just insert before next index (even if past end)
|
||||
RewriteOperation op = new InsertAfterOp(index, text); |
||||
List<RewriteOperation> rewrites = getProgram(programName); |
||||
op.instructionIndex = rewrites.size(); |
||||
rewrites.add(op); |
||||
} |
||||
|
||||
public void insertBefore(Token t, Object text) { |
||||
insertBefore(DEFAULT_PROGRAM_NAME, t, text); |
||||
} |
||||
|
||||
public void insertBefore(int index, Object text) { |
||||
insertBefore(DEFAULT_PROGRAM_NAME, index, text); |
||||
} |
||||
|
||||
public void insertBefore(String programName, Token t, Object text) { |
||||
insertBefore(programName, t.getTokenIndex(), text); |
||||
} |
||||
|
||||
public void insertBefore(String programName, int index, Object text) { |
||||
RewriteOperation op = new InsertBeforeOp(index,text); |
||||
List<RewriteOperation> rewrites = getProgram(programName); |
||||
op.instructionIndex = rewrites.size(); |
||||
rewrites.add(op); |
||||
} |
||||
|
||||
public void replace(int index, Object text) { |
||||
replace(DEFAULT_PROGRAM_NAME, index, index, text); |
||||
} |
||||
|
||||
public void replace(int from, int to, Object text) { |
||||
replace(DEFAULT_PROGRAM_NAME, from, to, text); |
||||
} |
||||
|
||||
public void replace(Token indexT, Object text) { |
||||
replace(DEFAULT_PROGRAM_NAME, indexT, indexT, text); |
||||
} |
||||
|
||||
public void replace(Token from, Token to, Object text) { |
||||
replace(DEFAULT_PROGRAM_NAME, from, to, text); |
||||
} |
||||
|
||||
public void replace(String programName, int from, int to, Object text) { |
||||
if ( from > to || from<0 || to<0 || to >= tokens.size() ) { |
||||
throw new IllegalArgumentException("replace: range invalid: "+from+".."+to+"(size="+tokens.size()+")"); |
||||
} |
||||
RewriteOperation op = new ReplaceOp(from, to, text); |
||||
List<RewriteOperation> rewrites = getProgram(programName); |
||||
op.instructionIndex = rewrites.size(); |
||||
rewrites.add(op); |
||||
} |
||||
|
||||
public void replace(String programName, Token from, Token to, Object text) { |
||||
replace(programName, |
||||
from.getTokenIndex(), |
||||
to.getTokenIndex(), |
||||
text); |
||||
} |
||||
|
||||
public void delete(int index) { |
||||
delete(DEFAULT_PROGRAM_NAME, index, index); |
||||
} |
||||
|
||||
public void delete(int from, int to) { |
||||
delete(DEFAULT_PROGRAM_NAME, from, to); |
||||
} |
||||
|
||||
public void delete(Token indexT) { |
||||
delete(DEFAULT_PROGRAM_NAME, indexT, indexT); |
||||
} |
||||
|
||||
public void delete(Token from, Token to) { |
||||
delete(DEFAULT_PROGRAM_NAME, from, to); |
||||
} |
||||
|
||||
public void delete(String programName, int from, int to) { |
||||
replace(programName,from,to,null); |
||||
} |
||||
|
||||
public void delete(String programName, Token from, Token to) { |
||||
replace(programName,from,to,null); |
||||
} |
||||
|
||||
public int getLastRewriteTokenIndex() { |
||||
return getLastRewriteTokenIndex(DEFAULT_PROGRAM_NAME); |
||||
} |
||||
|
||||
protected int getLastRewriteTokenIndex(String programName) { |
||||
Integer I = lastRewriteTokenIndexes.get(programName); |
||||
if ( I==null ) { |
||||
return -1; |
||||
} |
||||
return I; |
||||
} |
||||
|
||||
protected void setLastRewriteTokenIndex(String programName, int i) { |
||||
lastRewriteTokenIndexes.put(programName, i); |
||||
} |
||||
|
||||
protected List<RewriteOperation> getProgram(String name) { |
||||
List<RewriteOperation> is = programs.get(name); |
||||
if ( is==null ) { |
||||
is = initializeProgram(name); |
||||
} |
||||
return is; |
||||
} |
||||
|
||||
private List<RewriteOperation> initializeProgram(String name) { |
||||
List<RewriteOperation> is = new ArrayList<RewriteOperation>(PROGRAM_INIT_SIZE); |
||||
programs.put(name, is); |
||||
return is; |
||||
} |
||||
|
||||
/** Return the text from the original tokens altered per the |
||||
* instructions given to this rewriter. |
||||
*/ |
||||
public String getText() { |
||||
return getText(DEFAULT_PROGRAM_NAME, Interval.of(0,tokens.size()-1)); |
||||
} |
||||
|
||||
/** Return the text from the original tokens altered per the |
||||
* instructions given to this rewriter in programName. |
||||
*/ |
||||
public String getText(String programName) { |
||||
return getText(programName, Interval.of(0,tokens.size()-1)); |
||||
} |
||||
|
||||
/** Return the text associated with the tokens in the interval from the |
||||
* original token stream but with the alterations given to this rewriter. |
||||
* The interval refers to the indexes in the original token stream. |
||||
* We do not alter the token stream in any way, so the indexes |
||||
* and intervals are still consistent. Includes any operations done |
||||
* to the first and last token in the interval. So, if you did an |
||||
* insertBefore on the first token, you would get that insertion. |
||||
* The same is true if you do an insertAfter the stop token. |
||||
*/ |
||||
public String getText(Interval interval) { |
||||
return getText(DEFAULT_PROGRAM_NAME, interval); |
||||
} |
||||
|
||||
public String getText(String programName, Interval interval) { |
||||
List<RewriteOperation> rewrites = programs.get(programName); |
||||
int start = interval.a; |
||||
int stop = interval.b; |
||||
|
||||
// ensure start/end are in range
|
||||
if ( stop>tokens.size()-1 ) stop = tokens.size()-1; |
||||
if ( start<0 ) start = 0; |
||||
|
||||
if ( rewrites==null || rewrites.isEmpty() ) { |
||||
return tokens.getText(interval); // no instructions to execute
|
||||
} |
||||
StringBuilder buf = new StringBuilder(); |
||||
|
||||
// First, optimize instruction stream
|
||||
Map<Integer, RewriteOperation> indexToOp = reduceToSingleOperationPerIndex(rewrites); |
||||
|
||||
// Walk buffer, executing instructions and emitting tokens
|
||||
int i = start; |
||||
while ( i <= stop && i < tokens.size() ) { |
||||
RewriteOperation op = indexToOp.get(i); |
||||
indexToOp.remove(i); // remove so any left have index size-1
|
||||
Token t = tokens.get(i); |
||||
if ( op==null ) { |
||||
// no operation at that index, just dump token
|
||||
if ( t.getType()!=Token.EOF ) buf.append(t.getText()); |
||||
i++; // move to next token
|
||||
} |
||||
else { |
||||
i = op.execute(buf); // execute operation and skip
|
||||
} |
||||
} |
||||
|
||||
// include stuff after end if it's last index in buffer
|
||||
// So, if they did an insertAfter(lastValidIndex, "foo"), include
|
||||
// foo if end==lastValidIndex.
|
||||
if ( stop==tokens.size()-1 ) { |
||||
// Scan any remaining operations after last token
|
||||
// should be included (they will be inserts).
|
||||
for (RewriteOperation op : indexToOp.values()) { |
||||
if ( op.index >= tokens.size()-1 ) buf.append(op.text); |
||||
} |
||||
} |
||||
return buf.toString(); |
||||
} |
||||
|
||||
/** We need to combine operations and report invalid operations (like |
||||
* overlapping replaces that are not completed nested). Inserts to |
||||
* same index need to be combined etc... Here are the cases: |
||||
* |
||||
* I.i.u I.j.v leave alone, nonoverlapping |
||||
* I.i.u I.i.v combine: Iivu |
||||
* |
||||
* R.i-j.u R.x-y.v | i-j in x-y delete first R |
||||
* R.i-j.u R.i-j.v delete first R |
||||
* R.i-j.u R.x-y.v | x-y in i-j ERROR |
||||
* R.i-j.u R.x-y.v | boundaries overlap ERROR |
||||
* |
||||
* Delete special case of replace (text==null): |
||||
* D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right) |
||||
* |
||||
* I.i.u R.x-y.v | i in (x+1)-y delete I (since insert before |
||||
* we're not deleting i) |
||||
* I.i.u R.x-y.v | i not in (x+1)-y leave alone, nonoverlapping |
||||
* R.x-y.v I.i.u | i in x-y ERROR |
||||
* R.x-y.v I.x.u R.x-y.uv (combine, delete I) |
||||
* R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping |
||||
* |
||||
* I.i.u = insert u before op @ index i |
||||
* R.x-y.u = replace x-y indexed tokens with u |
||||
* |
||||
* First we need to examine replaces. For any replace op: |
||||
* |
||||
* 1. wipe out any insertions before op within that range. |
||||
* 2. Drop any replace op before that is contained completely within |
||||
* that range. |
||||
* 3. Throw exception upon boundary overlap with any previous replace. |
||||
* |
||||
* Then we can deal with inserts: |
||||
* |
||||
* 1. for any inserts to same index, combine even if not adjacent. |
||||
* 2. for any prior replace with same left boundary, combine this |
||||
* insert with replace and delete this replace. |
||||
* 3. throw exception if index in same range as previous replace |
||||
* |
||||
* Don't actually delete; make op null in list. Easier to walk list. |
||||
* Later we can throw as we add to index → op map. |
||||
* |
||||
* Note that I.2 R.2-2 will wipe out I.2 even though, technically, the |
||||
* inserted stuff would be before the replace range. But, if you |
||||
* add tokens in front of a method body '{' and then delete the method |
||||
* body, I think the stuff before the '{' you added should disappear too. |
||||
* |
||||
* Return a map from token index to operation. |
||||
*/ |
||||
protected Map<Integer, RewriteOperation> reduceToSingleOperationPerIndex(List<RewriteOperation> rewrites) { |
||||
// System.out.println("rewrites="+rewrites);
|
||||
|
||||
// WALK REPLACES
|
||||
for (int i = 0; i < rewrites.size(); i++) { |
||||
RewriteOperation op = rewrites.get(i); |
||||
if ( op==null ) continue; |
||||
if ( !(op instanceof ReplaceOp) ) continue; |
||||
ReplaceOp rop = (ReplaceOp)rewrites.get(i); |
||||
// Wipe prior inserts within range
|
||||
List<? extends InsertBeforeOp> inserts = getKindOfOps(rewrites, InsertBeforeOp.class, i); |
||||
for (InsertBeforeOp iop : inserts) { |
||||
if ( iop.index == rop.index ) { |
||||
// E.g., insert before 2, delete 2..2; update replace
|
||||
// text to include insert before, kill insert
|
||||
rewrites.set(iop.instructionIndex, null); |
||||
rop.text = iop.text.toString() + (rop.text!=null?rop.text.toString():""); |
||||
} |
||||
else if ( iop.index > rop.index && iop.index <= rop.lastIndex ) { |
||||
// delete insert as it's a no-op.
|
||||
rewrites.set(iop.instructionIndex, null); |
||||
} |
||||
} |
||||
// Drop any prior replaces contained within
|
||||
List<? extends ReplaceOp> prevReplaces = getKindOfOps(rewrites, ReplaceOp.class, i); |
||||
for (ReplaceOp prevRop : prevReplaces) { |
||||
if ( prevRop.index>=rop.index && prevRop.lastIndex <= rop.lastIndex ) { |
||||
// delete replace as it's a no-op.
|
||||
rewrites.set(prevRop.instructionIndex, null); |
||||
continue; |
||||
} |
||||
// throw exception unless disjoint or identical
|
||||
boolean disjoint = |
||||
prevRop.lastIndex<rop.index || prevRop.index > rop.lastIndex; |
||||
// Delete special case of replace (text==null):
|
||||
// D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right)
|
||||
if ( prevRop.text==null && rop.text==null && !disjoint ) { |
||||
//System.out.println("overlapping deletes: "+prevRop+", "+rop);
|
||||
rewrites.set(prevRop.instructionIndex, null); // kill first delete
|
||||
rop.index = Math.min(prevRop.index, rop.index); |
||||
rop.lastIndex = Math.max(prevRop.lastIndex, rop.lastIndex); |
||||
System.out.println("new rop "+rop); |
||||
} |
||||
else if ( !disjoint ) { |
||||
throw new IllegalArgumentException("replace op boundaries of "+rop+" overlap with previous "+prevRop); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// WALK INSERTS
|
||||
for (int i = 0; i < rewrites.size(); i++) { |
||||
RewriteOperation op = rewrites.get(i); |
||||
if ( op==null ) continue; |
||||
if ( !(op instanceof InsertBeforeOp) ) continue; |
||||
InsertBeforeOp iop = (InsertBeforeOp)rewrites.get(i); |
||||
// combine current insert with prior if any at same index
|
||||
List<? extends InsertBeforeOp> prevInserts = getKindOfOps(rewrites, InsertBeforeOp.class, i); |
||||
for (InsertBeforeOp prevIop : prevInserts) { |
||||
if ( prevIop.index==iop.index ) { |
||||
if ( InsertAfterOp.class.isInstance(prevIop) ) { |
||||
iop.text = catOpText(prevIop.text, iop.text); |
||||
rewrites.set(prevIop.instructionIndex, null); |
||||
} |
||||
else if ( InsertBeforeOp.class.isInstance(prevIop) ) { // combine objects
|
||||
// convert to strings...we're in process of toString'ing
|
||||
// whole token buffer so no lazy eval issue with any templates
|
||||
iop.text = catOpText(iop.text, prevIop.text); |
||||
// delete redundant prior insert
|
||||
rewrites.set(prevIop.instructionIndex, null); |
||||
} |
||||
} |
||||
} |
||||
// look for replaces where iop.index is in range; error
|
||||
List<? extends ReplaceOp> prevReplaces = getKindOfOps(rewrites, ReplaceOp.class, i); |
||||
for (ReplaceOp rop : prevReplaces) { |
||||
if ( iop.index == rop.index ) { |
||||
rop.text = catOpText(iop.text,rop.text); |
||||
rewrites.set(i, null); // delete current insert
|
||||
continue; |
||||
} |
||||
if ( iop.index >= rop.index && iop.index <= rop.lastIndex ) { |
||||
throw new IllegalArgumentException("insert op "+iop+" within boundaries of previous "+rop); |
||||
} |
||||
} |
||||
} |
||||
// System.out.println("rewrites after="+rewrites);
|
||||
Map<Integer, RewriteOperation> m = new HashMap<Integer, RewriteOperation>(); |
||||
for (int i = 0; i < rewrites.size(); i++) { |
||||
RewriteOperation op = rewrites.get(i); |
||||
if ( op==null ) continue; // ignore deleted ops
|
||||
if ( m.get(op.index)!=null ) { |
||||
throw new Error("should only be one op per index"); |
||||
} |
||||
m.put(op.index, op); |
||||
} |
||||
//System.out.println("index to op: "+m);
|
||||
return m; |
||||
} |
||||
|
||||
protected String catOpText(Object a, Object b) { |
||||
String x = ""; |
||||
String y = ""; |
||||
if ( a!=null ) x = a.toString(); |
||||
if ( b!=null ) y = b.toString(); |
||||
return x+y; |
||||
} |
||||
|
||||
/** Get all operations before an index of a particular kind */ |
||||
protected <T extends RewriteOperation> List<? extends T> getKindOfOps(List<? extends RewriteOperation> rewrites, Class<T> kind, int before) { |
||||
List<T> ops = new ArrayList<T>(); |
||||
for (int i=0; i<before && i<rewrites.size(); i++) { |
||||
RewriteOperation op = rewrites.get(i); |
||||
if ( op==null ) continue; // ignore deleted
|
||||
if ( kind.isInstance(op) ) { |
||||
ops.add(kind.cast(op)); |
||||
} |
||||
} |
||||
return ops; |
||||
} |
||||
} |
@ -1,347 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.InputStreamReader; |
||||
import java.io.Reader; |
||||
import java.nio.charset.Charset; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.Arrays; |
||||
|
||||
/** Do not buffer up the entire char stream. It does keep a small buffer |
||||
* for efficiency and also buffers while a mark exists (set by the |
||||
* lookahead prediction in parser). "Unbuffered" here refers to fact |
||||
* that it doesn't buffer all data, not that's it's on demand loading of char. |
||||
* |
||||
* Before 4.7, this class used the default environment encoding to convert |
||||
* bytes to UTF-16, and held the UTF-16 bytes in the buffer as chars. |
||||
* |
||||
* As of 4.7, the class uses UTF-8 by default, and the buffer holds Unicode |
||||
* code points in the buffer as ints. |
||||
*/ |
||||
public class UnbufferedCharStream implements CharStream { |
||||
/** |
||||
* A moving window buffer of the data being scanned. While there's a marker, |
||||
* we keep adding to buffer. Otherwise, {@link #consume consume()} resets so |
||||
* we start filling at index 0 again. |
||||
*/ |
||||
protected int[] data; |
||||
|
||||
/** |
||||
* The number of characters currently in {@link #data data}. |
||||
* |
||||
* <p>This is not the buffer capacity, that's {@code data.length}.</p> |
||||
*/ |
||||
protected int n; |
||||
|
||||
/** |
||||
* 0..n-1 index into {@link #data data} of next character. |
||||
* |
||||
* <p>The {@code LA(1)} character is {@code data[p]}. If {@code p == n}, we are |
||||
* out of buffered characters.</p> |
||||
*/ |
||||
protected int p=0; |
||||
|
||||
/** |
||||
* Count up with {@link #mark mark()} and down with |
||||
* {@link #release release()}. When we {@code release()} the last mark, |
||||
* {@code numMarkers} reaches 0 and we reset the buffer. Copy |
||||
* {@code data[p]..data[n-1]} to {@code data[0]..data[(n-1)-p]}. |
||||
*/ |
||||
protected int numMarkers = 0; |
||||
|
||||
/** |
||||
* This is the {@code LA(-1)} character for the current position. |
||||
*/ |
||||
protected int lastChar = -1; |
||||
|
||||
/** |
||||
* When {@code numMarkers > 0}, this is the {@code LA(-1)} character for the |
||||
* first character in {@link #data data}. Otherwise, this is unspecified. |
||||
*/ |
||||
protected int lastCharBufferStart; |
||||
|
||||
/** |
||||
* Absolute character index. It's the index of the character about to be |
||||
* read via {@code LA(1)}. Goes from 0 to the number of characters in the |
||||
* entire stream, although the stream size is unknown before the end is |
||||
* reached. |
||||
*/ |
||||
protected int currentCharIndex = 0; |
||||
|
||||
protected Reader input; |
||||
|
||||
/** The name or source of this char stream. */ |
||||
public String name; |
||||
|
||||
/** Useful for subclasses that pull char from other than this.input. */ |
||||
public UnbufferedCharStream() { |
||||
this(256); |
||||
} |
||||
|
||||
/** Useful for subclasses that pull char from other than this.input. */ |
||||
public UnbufferedCharStream(int bufferSize) { |
||||
n = 0; |
||||
data = new int[bufferSize]; |
||||
} |
||||
|
||||
public UnbufferedCharStream(InputStream input) { |
||||
this(input, 256); |
||||
} |
||||
|
||||
public UnbufferedCharStream(Reader input) { |
||||
this(input, 256); |
||||
} |
||||
|
||||
public UnbufferedCharStream(InputStream input, int bufferSize) { |
||||
this(input, bufferSize, StandardCharsets.UTF_8); |
||||
} |
||||
|
||||
public UnbufferedCharStream(InputStream input, int bufferSize, Charset charset) { |
||||
this(bufferSize); |
||||
this.input = new InputStreamReader(input, charset); |
||||
fill(1); // prime
|
||||
} |
||||
|
||||
public UnbufferedCharStream(Reader input, int bufferSize) { |
||||
this(bufferSize); |
||||
this.input = input; |
||||
fill(1); // prime
|
||||
} |
||||
|
||||
@Override |
||||
public void consume() { |
||||
if (LA(1) == IntStream.EOF) { |
||||
throw new IllegalStateException("cannot consume EOF"); |
||||
} |
||||
|
||||
// buf always has at least data[p==0] in this method due to ctor
|
||||
lastChar = data[p]; // track last char for LA(-1)
|
||||
|
||||
if (p == n-1 && numMarkers==0) { |
||||
n = 0; |
||||
p = -1; // p++ will leave this at 0
|
||||
lastCharBufferStart = lastChar; |
||||
} |
||||
|
||||
p++; |
||||
currentCharIndex++; |
||||
sync(1); |
||||
} |
||||
|
||||
/** |
||||
* Make sure we have 'need' elements from current position {@link #p p}. |
||||
* Last valid {@code p} index is {@code data.length-1}. {@code p+need-1} is |
||||
* the char index 'need' elements ahead. If we need 1 element, |
||||
* {@code (p+1-1)==p} must be less than {@code data.length}. |
||||
*/ |
||||
protected void sync(int want) { |
||||
int need = (p+want-1) - n + 1; // how many more elements we need?
|
||||
if ( need > 0 ) { |
||||
fill(need); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Add {@code n} characters to the buffer. Returns the number of characters |
||||
* actually added to the buffer. If the return value is less than {@code n}, |
||||
* then EOF was reached before {@code n} characters could be added. |
||||
*/ |
||||
protected int fill(int n) { |
||||
for (int i=0; i<n; i++) { |
||||
if (this.n > 0 && data[this.n - 1] == IntStream.EOF) { |
||||
return i; |
||||
} |
||||
|
||||
try { |
||||
int c = nextChar(); |
||||
if (c > Character.MAX_VALUE || c == IntStream.EOF) { |
||||
add(c); |
||||
} |
||||
else { |
||||
char ch = (char) c; |
||||
if (Character.isLowSurrogate(ch)) { |
||||
throw new RuntimeException("Invalid UTF-16 (low surrogate with no preceding high surrogate)"); |
||||
} |
||||
else if (Character.isHighSurrogate(ch)) { |
||||
int lowSurrogate = nextChar(); |
||||
if (lowSurrogate > Character.MAX_VALUE) { |
||||
throw new RuntimeException("Invalid UTF-16 (high surrogate followed by code point > U+FFFF"); |
||||
} |
||||
else if (lowSurrogate == IntStream.EOF) { |
||||
throw new RuntimeException("Invalid UTF-16 (dangling high surrogate at end of file)"); |
||||
} |
||||
else { |
||||
char lowSurrogateChar = (char) lowSurrogate; |
||||
if (Character.isLowSurrogate(lowSurrogateChar)) { |
||||
add(Character.toCodePoint(ch, lowSurrogateChar)); |
||||
} |
||||
else { |
||||
throw new RuntimeException("Invalid UTF-16 (dangling high surrogate"); |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
add(c); |
||||
} |
||||
} |
||||
} |
||||
catch (IOException ioe) { |
||||
throw new RuntimeException(ioe); |
||||
} |
||||
} |
||||
|
||||
return n; |
||||
} |
||||
|
||||
/** |
||||
* Override to provide different source of characters than |
||||
* {@link #input input}. |
||||
*/ |
||||
protected int nextChar() throws IOException { |
||||
return input.read(); |
||||
} |
||||
|
||||
protected void add(int c) { |
||||
if ( n>=data.length ) { |
||||
data = Arrays.copyOf(data, data.length * 2); |
||||
} |
||||
data[n++] = c; |
||||
} |
||||
|
||||
@Override |
||||
public int LA(int i) { |
||||
if ( i==-1 ) return lastChar; // special case
|
||||
sync(i); |
||||
int index = p + i - 1; |
||||
if ( index < 0 ) throw new IndexOutOfBoundsException(); |
||||
if ( index >= n ) return IntStream.EOF; |
||||
return data[index]; |
||||
} |
||||
|
||||
/** |
||||
* Return a marker that we can release later. |
||||
* |
||||
* <p>The specific marker value used for this class allows for some level of |
||||
* protection against misuse where {@code seek()} is called on a mark or |
||||
* {@code release()} is called in the wrong order.</p> |
||||
*/ |
||||
@Override |
||||
public int mark() { |
||||
if (numMarkers == 0) { |
||||
lastCharBufferStart = lastChar; |
||||
} |
||||
|
||||
int mark = -numMarkers - 1; |
||||
numMarkers++; |
||||
return mark; |
||||
} |
||||
|
||||
/** Decrement number of markers, resetting buffer if we hit 0. |
||||
* @param marker |
||||
*/ |
||||
@Override |
||||
public void release(int marker) { |
||||
int expectedMark = -numMarkers; |
||||
if ( marker!=expectedMark ) { |
||||
throw new IllegalStateException("release() called with an invalid marker."); |
||||
} |
||||
|
||||
numMarkers--; |
||||
if ( numMarkers==0 && p > 0 ) { // release buffer when we can, but don't do unnecessary work
|
||||
// Copy data[p]..data[n-1] to data[0]..data[(n-1)-p], reset ptrs
|
||||
// p is last valid char; move nothing if p==n as we have no valid char
|
||||
System.arraycopy(data, p, data, 0, n - p); // shift n-p char from p to 0
|
||||
n = n - p; |
||||
p = 0; |
||||
lastCharBufferStart = lastChar; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int index() { |
||||
return currentCharIndex; |
||||
} |
||||
|
||||
/** Seek to absolute character index, which might not be in the current |
||||
* sliding window. Move {@code p} to {@code index-bufferStartIndex}. |
||||
*/ |
||||
@Override |
||||
public void seek(int index) { |
||||
if (index == currentCharIndex) { |
||||
return; |
||||
} |
||||
|
||||
if (index > currentCharIndex) { |
||||
sync(index - currentCharIndex); |
||||
index = Math.min(index, getBufferStartIndex() + n - 1); |
||||
} |
||||
|
||||
// index == to bufferStartIndex should set p to 0
|
||||
int i = index - getBufferStartIndex(); |
||||
if ( i < 0 ) { |
||||
throw new IllegalArgumentException("cannot seek to negative index " + index); |
||||
} |
||||
else if (i >= n) { |
||||
throw new UnsupportedOperationException("seek to index outside buffer: "+ |
||||
index+" not in "+getBufferStartIndex()+".."+(getBufferStartIndex()+n)); |
||||
} |
||||
|
||||
p = i; |
||||
currentCharIndex = index; |
||||
if (p == 0) { |
||||
lastChar = lastCharBufferStart; |
||||
} |
||||
else { |
||||
lastChar = data[p-1]; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
throw new UnsupportedOperationException("Unbuffered stream cannot know its size"); |
||||
} |
||||
|
||||
@Override |
||||
public String getSourceName() { |
||||
if (name == null || name.isEmpty()) { |
||||
return UNKNOWN_SOURCE_NAME; |
||||
} |
||||
|
||||
return name; |
||||
} |
||||
|
||||
@Override |
||||
public String getText(Interval interval) { |
||||
if (interval.a < 0 || interval.b < interval.a - 1) { |
||||
throw new IllegalArgumentException("invalid interval"); |
||||
} |
||||
|
||||
int bufferStartIndex = getBufferStartIndex(); |
||||
if (n > 0 && data[n - 1] == Character.MAX_VALUE) { |
||||
if (interval.a + interval.length() > bufferStartIndex + n) { |
||||
throw new IllegalArgumentException("the interval extends past the end of the stream"); |
||||
} |
||||
} |
||||
|
||||
if (interval.a < bufferStartIndex || interval.b >= bufferStartIndex + n) { |
||||
throw new UnsupportedOperationException("interval "+interval+" outside buffer: "+ |
||||
bufferStartIndex+".."+(bufferStartIndex+n-1)); |
||||
} |
||||
// convert from absolute to local index
|
||||
int i = interval.a - bufferStartIndex; |
||||
return new String(data, i, interval.length()); |
||||
} |
||||
|
||||
protected final int getBufferStartIndex() { |
||||
return currentCharIndex - p; |
||||
} |
||||
} |
@ -1,311 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
public class UnbufferedTokenStream<T extends Token> implements TokenStream { |
||||
protected TokenSource tokenSource; |
||||
|
||||
/** |
||||
* A moving window buffer of the data being scanned. While there's a marker, |
||||
* we keep adding to buffer. Otherwise, {@link #consume consume()} resets so |
||||
* we start filling at index 0 again. |
||||
*/ |
||||
protected Token[] tokens; |
||||
|
||||
/** |
||||
* The number of tokens currently in {@link #tokens tokens}. |
||||
* |
||||
* <p>This is not the buffer capacity, that's {@code tokens.length}.</p> |
||||
*/ |
||||
protected int n; |
||||
|
||||
/** |
||||
* 0..n-1 index into {@link #tokens tokens} of next token. |
||||
* |
||||
* <p>The {@code LT(1)} token is {@code tokens[p]}. If {@code p == n}, we are |
||||
* out of buffered tokens.</p> |
||||
*/ |
||||
protected int p=0; |
||||
|
||||
/** |
||||
* Count up with {@link #mark mark()} and down with |
||||
* {@link #release release()}. When we {@code release()} the last mark, |
||||
* {@code numMarkers} reaches 0 and we reset the buffer. Copy |
||||
* {@code tokens[p]..tokens[n-1]} to {@code tokens[0]..tokens[(n-1)-p]}. |
||||
*/ |
||||
protected int numMarkers = 0; |
||||
|
||||
/** |
||||
* This is the {@code LT(-1)} token for the current position. |
||||
*/ |
||||
protected Token lastToken; |
||||
|
||||
/** |
||||
* When {@code numMarkers > 0}, this is the {@code LT(-1)} token for the |
||||
* first token in {@link #tokens}. Otherwise, this is {@code null}. |
||||
*/ |
||||
protected Token lastTokenBufferStart; |
||||
|
||||
/** |
||||
* Absolute token index. It's the index of the token about to be read via |
||||
* {@code LT(1)}. Goes from 0 to the number of tokens in the entire stream, |
||||
* although the stream size is unknown before the end is reached. |
||||
* |
||||
* <p>This value is used to set the token indexes if the stream provides tokens |
||||
* that implement {@link WritableToken}.</p> |
||||
*/ |
||||
protected int currentTokenIndex = 0; |
||||
|
||||
public UnbufferedTokenStream(TokenSource tokenSource) { |
||||
this(tokenSource, 256); |
||||
} |
||||
|
||||
public UnbufferedTokenStream(TokenSource tokenSource, int bufferSize) { |
||||
this.tokenSource = tokenSource; |
||||
tokens = new Token[bufferSize]; |
||||
n = 0; |
||||
fill(1); // prime the pump
|
||||
} |
||||
|
||||
@Override |
||||
public Token get(int i) { // get absolute index
|
||||
int bufferStartIndex = getBufferStartIndex(); |
||||
if (i < bufferStartIndex || i >= bufferStartIndex + n) { |
||||
throw new IndexOutOfBoundsException("get("+i+") outside buffer: "+ |
||||
bufferStartIndex+".."+(bufferStartIndex+n)); |
||||
} |
||||
return tokens[i - bufferStartIndex]; |
||||
} |
||||
|
||||
@Override |
||||
public Token LT(int i) { |
||||
if ( i==-1 ) { |
||||
return lastToken; |
||||
} |
||||
|
||||
sync(i); |
||||
int index = p + i - 1; |
||||
if ( index < 0 ) { |
||||
throw new IndexOutOfBoundsException("LT("+i+") gives negative index"); |
||||
} |
||||
|
||||
if ( index >= n ) { |
||||
assert n > 0 && tokens[n-1].getType() == Token.EOF; |
||||
return tokens[n-1]; |
||||
} |
||||
|
||||
return tokens[index]; |
||||
} |
||||
|
||||
@Override |
||||
public int LA(int i) { |
||||
return LT(i).getType(); |
||||
} |
||||
|
||||
@Override |
||||
public TokenSource getTokenSource() { |
||||
return tokenSource; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String getText() { |
||||
return ""; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String getText(RuleContext ctx) { |
||||
return getText(ctx.getSourceInterval()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String getText(Token start, Token stop) { |
||||
return getText(Interval.of(start.getTokenIndex(), stop.getTokenIndex())); |
||||
} |
||||
|
||||
@Override |
||||
public void consume() { |
||||
if (LA(1) == Token.EOF) { |
||||
throw new IllegalStateException("cannot consume EOF"); |
||||
} |
||||
|
||||
// buf always has at least tokens[p==0] in this method due to ctor
|
||||
lastToken = tokens[p]; // track last token for LT(-1)
|
||||
|
||||
// if we're at last token and no markers, opportunity to flush buffer
|
||||
if ( p == n-1 && numMarkers==0 ) { |
||||
n = 0; |
||||
p = -1; // p++ will leave this at 0
|
||||
lastTokenBufferStart = lastToken; |
||||
} |
||||
|
||||
p++; |
||||
currentTokenIndex++; |
||||
sync(1); |
||||
} |
||||
|
||||
/** Make sure we have 'need' elements from current position {@link #p p}. Last valid |
||||
* {@code p} index is {@code tokens.length-1}. {@code p+need-1} is the tokens index 'need' elements |
||||
* ahead. If we need 1 element, {@code (p+1-1)==p} must be less than {@code tokens.length}. |
||||
*/ |
||||
protected void sync(int want) { |
||||
int need = (p+want-1) - n + 1; // how many more elements we need?
|
||||
if ( need > 0 ) { |
||||
fill(need); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Add {@code n} elements to the buffer. Returns the number of tokens |
||||
* actually added to the buffer. If the return value is less than {@code n}, |
||||
* then EOF was reached before {@code n} tokens could be added. |
||||
*/ |
||||
protected int fill(int n) { |
||||
for (int i=0; i<n; i++) { |
||||
if (this.n > 0 && tokens[this.n-1].getType() == Token.EOF) { |
||||
return i; |
||||
} |
||||
|
||||
Token t = tokenSource.nextToken(); |
||||
add(t); |
||||
} |
||||
|
||||
return n; |
||||
} |
||||
|
||||
protected void add(Token t) { |
||||
if ( n>=tokens.length ) { |
||||
tokens = Arrays.copyOf(tokens, tokens.length * 2); |
||||
} |
||||
|
||||
if (t instanceof WritableToken) { |
||||
((WritableToken)t).setTokenIndex(getBufferStartIndex() + n); |
||||
} |
||||
|
||||
tokens[n++] = t; |
||||
} |
||||
|
||||
/** |
||||
* Return a marker that we can release later. |
||||
* |
||||
* <p>The specific marker value used for this class allows for some level of |
||||
* protection against misuse where {@code seek()} is called on a mark or |
||||
* {@code release()} is called in the wrong order.</p> |
||||
*/ |
||||
@Override |
||||
public int mark() { |
||||
if (numMarkers == 0) { |
||||
lastTokenBufferStart = lastToken; |
||||
} |
||||
|
||||
int mark = -numMarkers - 1; |
||||
numMarkers++; |
||||
return mark; |
||||
} |
||||
|
||||
@Override |
||||
public void release(int marker) { |
||||
int expectedMark = -numMarkers; |
||||
if ( marker!=expectedMark ) { |
||||
throw new IllegalStateException("release() called with an invalid marker."); |
||||
} |
||||
|
||||
numMarkers--; |
||||
if ( numMarkers==0 ) { // can we release buffer?
|
||||
if (p > 0) { |
||||
// Copy tokens[p]..tokens[n-1] to tokens[0]..tokens[(n-1)-p], reset ptrs
|
||||
// p is last valid token; move nothing if p==n as we have no valid char
|
||||
System.arraycopy(tokens, p, tokens, 0, n - p); // shift n-p tokens from p to 0
|
||||
n = n - p; |
||||
p = 0; |
||||
} |
||||
|
||||
lastTokenBufferStart = lastToken; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int index() { |
||||
return currentTokenIndex; |
||||
} |
||||
|
||||
@Override |
||||
public void seek(int index) { // seek to absolute index
|
||||
if (index == currentTokenIndex) { |
||||
return; |
||||
} |
||||
|
||||
if (index > currentTokenIndex) { |
||||
sync(index - currentTokenIndex); |
||||
index = Math.min(index, getBufferStartIndex() + n - 1); |
||||
} |
||||
|
||||
int bufferStartIndex = getBufferStartIndex(); |
||||
int i = index - bufferStartIndex; |
||||
if ( i < 0 ) { |
||||
throw new IllegalArgumentException("cannot seek to negative index " + index); |
||||
} |
||||
else if (i >= n) { |
||||
throw new UnsupportedOperationException("seek to index outside buffer: "+ |
||||
index+" not in "+ bufferStartIndex +".."+(bufferStartIndex +n)); |
||||
} |
||||
|
||||
p = i; |
||||
currentTokenIndex = index; |
||||
if (p == 0) { |
||||
lastToken = lastTokenBufferStart; |
||||
} |
||||
else { |
||||
lastToken = tokens[p-1]; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
throw new UnsupportedOperationException("Unbuffered stream cannot know its size"); |
||||
} |
||||
|
||||
@Override |
||||
public String getSourceName() { |
||||
return tokenSource.getSourceName(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String getText(Interval interval) { |
||||
int bufferStartIndex = getBufferStartIndex(); |
||||
int bufferStopIndex = bufferStartIndex + tokens.length - 1; |
||||
|
||||
int start = interval.a; |
||||
int stop = interval.b; |
||||
if (start < bufferStartIndex || stop > bufferStopIndex) { |
||||
throw new UnsupportedOperationException("interval "+interval+" not in token buffer window: "+ |
||||
bufferStartIndex+".."+bufferStopIndex); |
||||
} |
||||
|
||||
int a = start - bufferStartIndex; |
||||
int b = stop - bufferStartIndex; |
||||
|
||||
StringBuilder buf = new StringBuilder(); |
||||
for (int i = a; i <= b; i++) { |
||||
Token t = tokens[i]; |
||||
buf.append(t.getText()); |
||||
} |
||||
|
||||
return buf.toString(); |
||||
} |
||||
|
||||
protected final int getBufferStartIndex() { |
||||
return currentTokenIndex - p; |
||||
} |
||||
} |
@ -1,127 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
/** |
||||
* This interface provides information about the vocabulary used by a |
||||
* recognizer. |
||||
* |
||||
* @see Recognizer#getVocabulary() |
||||
* @author Sam Harwell |
||||
*/ |
||||
public interface Vocabulary { |
||||
/** |
||||
* Returns the highest token type value. It can be used to iterate from |
||||
* zero to that number, inclusively, thus querying all stored entries. |
||||
* @return the highest token type value |
||||
*/ |
||||
int getMaxTokenType(); |
||||
|
||||
/** |
||||
* Gets the string literal associated with a token type. The string returned |
||||
* by this method, when not {@code null}, can be used unaltered in a parser |
||||
* grammar to represent this token type. |
||||
* |
||||
* <p>The following table shows examples of lexer rules and the literal |
||||
* names assigned to the corresponding token types.</p> |
||||
* |
||||
* <table> |
||||
* <tr> |
||||
* <th>Rule</th> |
||||
* <th>Literal Name</th> |
||||
* <th>Java String Literal</th> |
||||
* </tr> |
||||
* <tr> |
||||
* <td>{@code THIS : 'this';}</td> |
||||
* <td>{@code 'this'}</td> |
||||
* <td>{@code "'this'"}</td> |
||||
* </tr> |
||||
* <tr> |
||||
* <td>{@code SQUOTE : '\'';}</td> |
||||
* <td>{@code '\''}</td> |
||||
* <td>{@code "'\\''"}</td> |
||||
* </tr> |
||||
* <tr> |
||||
* <td>{@code ID : [A-Z]+;}</td> |
||||
* <td>n/a</td> |
||||
* <td>{@code null}</td> |
||||
* </tr> |
||||
* </table> |
||||
* |
||||
* @param tokenType The token type. |
||||
* |
||||
* @return The string literal associated with the specified token type, or |
||||
* {@code null} if no string literal is associated with the type. |
||||
*/ |
||||
String getLiteralName(int tokenType); |
||||
|
||||
/** |
||||
* Gets the symbolic name associated with a token type. The string returned |
||||
* by this method, when not {@code null}, can be used unaltered in a parser |
||||
* grammar to represent this token type. |
||||
* |
||||
* <p>This method supports token types defined by any of the following |
||||
* methods:</p> |
||||
* |
||||
* <ul> |
||||
* <li>Tokens created by lexer rules.</li> |
||||
* <li>Tokens defined in a <code>tokens{}</code> block in a lexer or parser |
||||
* grammar.</li> |
||||
* <li>The implicitly defined {@code EOF} token, which has the token type |
||||
* {@link Token#EOF}.</li> |
||||
* </ul> |
||||
* |
||||
* <p>The following table shows examples of lexer rules and the literal |
||||
* names assigned to the corresponding token types.</p> |
||||
* |
||||
* <table> |
||||
* <tr> |
||||
* <th>Rule</th> |
||||
* <th>Symbolic Name</th> |
||||
* </tr> |
||||
* <tr> |
||||
* <td>{@code THIS : 'this';}</td> |
||||
* <td>{@code THIS}</td> |
||||
* </tr> |
||||
* <tr> |
||||
* <td>{@code SQUOTE : '\'';}</td> |
||||
* <td>{@code SQUOTE}</td> |
||||
* </tr> |
||||
* <tr> |
||||
* <td>{@code ID : [A-Z]+;}</td> |
||||
* <td>{@code ID}</td> |
||||
* </tr> |
||||
* </table> |
||||
* |
||||
* @param tokenType The token type. |
||||
* |
||||
* @return The symbolic name associated with the specified token type, or |
||||
* {@code null} if no symbolic name is associated with the type. |
||||
*/ |
||||
String getSymbolicName(int tokenType); |
||||
|
||||
/** |
||||
* Gets the display name of a token type. |
||||
* |
||||
* <p>ANTLR provides a default implementation of this method, but |
||||
* applications are free to override the behavior in any manner which makes |
||||
* sense for the application. The default implementation returns the first |
||||
* result from the following list which produces a non-{@code null} |
||||
* result.</p> |
||||
* |
||||
* <ol> |
||||
* <li>The result of {@link #getLiteralName}</li> |
||||
* <li>The result of {@link #getSymbolicName}</li> |
||||
* <li>The result of {@link Integer#toString}</li> |
||||
* </ol> |
||||
* |
||||
* @param tokenType The token type. |
||||
* |
||||
* @return The display name of the token type, for use in error reporting or |
||||
* other user-visible messages which reference specific token types. |
||||
*/ |
||||
String getDisplayName(int tokenType); |
||||
} |
@ -1,176 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
/** |
||||
* This class provides a default implementation of the {@link Vocabulary} |
||||
* interface. |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public class VocabularyImpl implements Vocabulary { |
||||
private static final String[] EMPTY_NAMES = new String[0]; |
||||
|
||||
/** |
||||
* Gets an empty {@link Vocabulary} instance. |
||||
* |
||||
* <p> |
||||
* No literal or symbol names are assigned to token types, so |
||||
* {@link #getDisplayName(int)} returns the numeric value for all tokens |
||||
* except {@link Token#EOF}.</p> |
||||
*/ |
||||
public static final VocabularyImpl EMPTY_VOCABULARY = new VocabularyImpl(EMPTY_NAMES, EMPTY_NAMES, EMPTY_NAMES); |
||||
|
||||
|
||||
private final String[] literalNames; |
||||
|
||||
private final String[] symbolicNames; |
||||
|
||||
private final String[] displayNames; |
||||
|
||||
private final int maxTokenType; |
||||
|
||||
/** |
||||
* Constructs a new instance of {@link VocabularyImpl} from the specified |
||||
* literal and symbolic token names. |
||||
* |
||||
* @param literalNames The literal names assigned to tokens, or {@code null} |
||||
* if no literal names are assigned. |
||||
* @param symbolicNames The symbolic names assigned to tokens, or |
||||
* {@code null} if no symbolic names are assigned. |
||||
* |
||||
* @see #getLiteralName(int) |
||||
* @see #getSymbolicName(int) |
||||
*/ |
||||
public VocabularyImpl(String[] literalNames, String[] symbolicNames) { |
||||
this(literalNames, symbolicNames, null); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new instance of {@link VocabularyImpl} from the specified |
||||
* literal, symbolic, and display token names. |
||||
* |
||||
* @param literalNames The literal names assigned to tokens, or {@code null} |
||||
* if no literal names are assigned. |
||||
* @param symbolicNames The symbolic names assigned to tokens, or |
||||
* {@code null} if no symbolic names are assigned. |
||||
* @param displayNames The display names assigned to tokens, or {@code null} |
||||
* to use the values in {@code literalNames} and {@code symbolicNames} as |
||||
* the source of display names, as described in |
||||
* {@link #getDisplayName(int)}. |
||||
* |
||||
* @see #getLiteralName(int) |
||||
* @see #getSymbolicName(int) |
||||
* @see #getDisplayName(int) |
||||
*/ |
||||
public VocabularyImpl(String[] literalNames, String[] symbolicNames, String[] displayNames) { |
||||
this.literalNames = literalNames != null ? literalNames : EMPTY_NAMES; |
||||
this.symbolicNames = symbolicNames != null ? symbolicNames : EMPTY_NAMES; |
||||
this.displayNames = displayNames != null ? displayNames : EMPTY_NAMES; |
||||
// See note here on -1 part: https://github.com/antlr/antlr4/pull/1146
|
||||
this.maxTokenType = |
||||
Math.max(this.displayNames.length, |
||||
Math.max(this.literalNames.length, this.symbolicNames.length)) - 1; |
||||
} |
||||
|
||||
/** |
||||
* Returns a {@link VocabularyImpl} instance from the specified set of token |
||||
* names. This method acts as a compatibility layer for the single |
||||
* {@code tokenNames} array generated by previous releases of ANTLR. |
||||
* |
||||
* <p>The resulting vocabulary instance returns {@code null} for |
||||
* {@link #getLiteralName(int)} and {@link #getSymbolicName(int)}, and the |
||||
* value from {@code tokenNames} for the display names.</p> |
||||
* |
||||
* @param tokenNames The token names, or {@code null} if no token names are |
||||
* available. |
||||
* @return A {@link Vocabulary} instance which uses {@code tokenNames} for |
||||
* the display names of tokens. |
||||
*/ |
||||
public static Vocabulary fromTokenNames(String[] tokenNames) { |
||||
if (tokenNames == null || tokenNames.length == 0) { |
||||
return EMPTY_VOCABULARY; |
||||
} |
||||
|
||||
String[] literalNames = Arrays.copyOf(tokenNames, tokenNames.length); |
||||
String[] symbolicNames = Arrays.copyOf(tokenNames, tokenNames.length); |
||||
for (int i = 0; i < tokenNames.length; i++) { |
||||
String tokenName = tokenNames[i]; |
||||
if (tokenName == null) { |
||||
continue; |
||||
} |
||||
|
||||
if (!tokenName.isEmpty()) { |
||||
char firstChar = tokenName.charAt(0); |
||||
if (firstChar == '\'') { |
||||
symbolicNames[i] = null; |
||||
continue; |
||||
} |
||||
else if (Character.isUpperCase(firstChar)) { |
||||
literalNames[i] = null; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
// wasn't a literal or symbolic name
|
||||
literalNames[i] = null; |
||||
symbolicNames[i] = null; |
||||
} |
||||
|
||||
return new VocabularyImpl(literalNames, symbolicNames, tokenNames); |
||||
} |
||||
|
||||
@Override |
||||
public int getMaxTokenType() { |
||||
return maxTokenType; |
||||
} |
||||
|
||||
@Override |
||||
public String getLiteralName(int tokenType) { |
||||
if (tokenType >= 0 && tokenType < literalNames.length) { |
||||
return literalNames[tokenType]; |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public String getSymbolicName(int tokenType) { |
||||
if (tokenType >= 0 && tokenType < symbolicNames.length) { |
||||
return symbolicNames[tokenType]; |
||||
} |
||||
|
||||
if (tokenType == Token.EOF) { |
||||
return "EOF"; |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public String getDisplayName(int tokenType) { |
||||
if (tokenType >= 0 && tokenType < displayNames.length) { |
||||
String displayName = displayNames[tokenType]; |
||||
if (displayName != null) { |
||||
return displayName; |
||||
} |
||||
} |
||||
|
||||
String literalName = getLiteralName(tokenType); |
||||
if (literalName != null) { |
||||
return literalName; |
||||
} |
||||
|
||||
String symbolicName = getSymbolicName(tokenType); |
||||
if (symbolicName != null) { |
||||
return symbolicName; |
||||
} |
||||
|
||||
return Integer.toString(tokenType); |
||||
} |
||||
} |
@ -1,21 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime; |
||||
|
||||
public interface WritableToken extends Token { |
||||
public void setText(String text); |
||||
|
||||
public void setType(int ttype); |
||||
|
||||
public void setLine(int line); |
||||
|
||||
public void setCharPositionInLine(int pos); |
||||
|
||||
public void setChannel(int channel); |
||||
|
||||
public void setTokenIndex(int index); |
||||
} |
@ -1,196 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.ParserRuleContext; |
||||
import com.fr.third.org.antlr.v4.runtime.RuleContext; |
||||
import com.fr.third.org.antlr.v4.runtime.Token; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntervalSet; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** */ |
||||
public class ATN { |
||||
public static final int INVALID_ALT_NUMBER = 0; |
||||
|
||||
|
||||
public final List<ATNState> states = new ArrayList<ATNState>(); |
||||
|
||||
/** Each subrule/rule is a decision point and we must track them so we |
||||
* can go back later and build DFA predictors for them. This includes |
||||
* all the rules, subrules, optional blocks, ()+, ()* etc... |
||||
*/ |
||||
public final List<DecisionState> decisionToState = new ArrayList<DecisionState>(); |
||||
|
||||
/** |
||||
* Maps from rule index to starting state number. |
||||
*/ |
||||
public RuleStartState[] ruleToStartState; |
||||
|
||||
/** |
||||
* Maps from rule index to stop state number. |
||||
*/ |
||||
public RuleStopState[] ruleToStopState; |
||||
|
||||
|
||||
public final Map<String, TokensStartState> modeNameToStartState = |
||||
new LinkedHashMap<String, TokensStartState>(); |
||||
|
||||
/** |
||||
* The type of the ATN. |
||||
*/ |
||||
public final ATNType grammarType; |
||||
|
||||
/** |
||||
* The maximum value for any symbol recognized by a transition in the ATN. |
||||
*/ |
||||
public final int maxTokenType; |
||||
|
||||
/** |
||||
* For lexer ATNs, this maps the rule index to the resulting token type. |
||||
* For parser ATNs, this maps the rule index to the generated bypass token |
||||
* type if the |
||||
* {@link ATNDeserializationOptions#isGenerateRuleBypassTransitions} |
||||
* deserialization option was specified; otherwise, this is {@code null}. |
||||
*/ |
||||
public int[] ruleToTokenType; |
||||
|
||||
/** |
||||
* For lexer ATNs, this is an array of {@link LexerAction} objects which may |
||||
* be referenced by action transitions in the ATN. |
||||
*/ |
||||
public LexerAction[] lexerActions; |
||||
|
||||
public final List<TokensStartState> modeToStartState = new ArrayList<TokensStartState>(); |
||||
|
||||
/** Used for runtime deserialization of ATNs from strings */ |
||||
public ATN(ATNType grammarType, int maxTokenType) { |
||||
this.grammarType = grammarType; |
||||
this.maxTokenType = maxTokenType; |
||||
} |
||||
|
||||
/** Compute the set of valid tokens that can occur starting in state {@code s}. |
||||
* If {@code ctx} is null, the set of tokens will not include what can follow |
||||
* the rule surrounding {@code s}. In other words, the set will be |
||||
* restricted to tokens reachable staying within {@code s}'s rule. |
||||
*/ |
||||
public IntervalSet nextTokens(ATNState s, RuleContext ctx) { |
||||
LL1Analyzer anal = new LL1Analyzer(this); |
||||
IntervalSet next = anal.LOOK(s, ctx); |
||||
return next; |
||||
} |
||||
|
||||
/** |
||||
* Compute the set of valid tokens that can occur starting in {@code s} and |
||||
* staying in same rule. {@link Token#EPSILON} is in set if we reach end of |
||||
* rule. |
||||
*/ |
||||
public IntervalSet nextTokens(ATNState s) { |
||||
if ( s.nextTokenWithinRule != null ) return s.nextTokenWithinRule; |
||||
s.nextTokenWithinRule = nextTokens(s, null); |
||||
s.nextTokenWithinRule.setReadonly(true); |
||||
return s.nextTokenWithinRule; |
||||
} |
||||
|
||||
public void addState(ATNState state) { |
||||
if (state != null) { |
||||
state.atn = this; |
||||
state.stateNumber = states.size(); |
||||
} |
||||
|
||||
states.add(state); |
||||
} |
||||
|
||||
public void removeState(ATNState state) { |
||||
states.set(state.stateNumber, null); // just free mem, don't shift states in list
|
||||
} |
||||
|
||||
public int defineDecisionState(DecisionState s) { |
||||
decisionToState.add(s); |
||||
s.decision = decisionToState.size()-1; |
||||
return s.decision; |
||||
} |
||||
|
||||
public DecisionState getDecisionState(int decision) { |
||||
if ( !decisionToState.isEmpty() ) { |
||||
return decisionToState.get(decision); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public int getNumberOfDecisions() { |
||||
return decisionToState.size(); |
||||
} |
||||
|
||||
/** |
||||
* Computes the set of input symbols which could follow ATN state number |
||||
* {@code stateNumber} in the specified full {@code context}. This method |
||||
* considers the complete parser context, but does not evaluate semantic |
||||
* predicates (i.e. all predicates encountered during the calculation are |
||||
* assumed true). If a path in the ATN exists from the starting state to the |
||||
* {@link RuleStopState} of the outermost context without matching any |
||||
* symbols, {@link Token#EOF} is added to the returned set. |
||||
* |
||||
* <p>If {@code context} is {@code null}, it is treated as {@link ParserRuleContext#EMPTY}.</p> |
||||
* |
||||
* Note that this does NOT give you the set of all tokens that could |
||||
* appear at a given token position in the input phrase. In other words, |
||||
* it does not answer: |
||||
* |
||||
* "Given a specific partial input phrase, return the set of all tokens |
||||
* that can follow the last token in the input phrase." |
||||
* |
||||
* The big difference is that with just the input, the parser could |
||||
* land right in the middle of a lookahead decision. Getting |
||||
* all *possible* tokens given a partial input stream is a separate |
||||
* computation. See https://github.com/antlr/antlr4/issues/1428
|
||||
* |
||||
* For this function, we are specifying an ATN state and call stack to compute |
||||
* what token(s) can come next and specifically: outside of a lookahead decision. |
||||
* That is what you want for error reporting and recovery upon parse error. |
||||
* |
||||
* @param stateNumber the ATN state number |
||||
* @param context the full parse context |
||||
* @return The set of potentially valid input symbols which could follow the |
||||
* specified state in the specified context. |
||||
* @throws IllegalArgumentException if the ATN does not contain a state with |
||||
* number {@code stateNumber} |
||||
*/ |
||||
public IntervalSet getExpectedTokens(int stateNumber, RuleContext context) { |
||||
if (stateNumber < 0 || stateNumber >= states.size()) { |
||||
throw new IllegalArgumentException("Invalid state number."); |
||||
} |
||||
|
||||
RuleContext ctx = context; |
||||
ATNState s = states.get(stateNumber); |
||||
IntervalSet following = nextTokens(s); |
||||
if (!following.contains(Token.EPSILON)) { |
||||
return following; |
||||
} |
||||
|
||||
IntervalSet expected = new IntervalSet(); |
||||
expected.addAll(following); |
||||
expected.remove(Token.EPSILON); |
||||
while (ctx != null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) { |
||||
ATNState invokingState = states.get(ctx.invokingState); |
||||
RuleTransition rt = (RuleTransition)invokingState.transition(0); |
||||
following = nextTokens(rt.followState); |
||||
expected.addAll(following); |
||||
expected.remove(Token.EPSILON); |
||||
ctx = ctx.parent; |
||||
} |
||||
|
||||
if (following.contains(Token.EPSILON)) { |
||||
expected.add(Token.EOF); |
||||
} |
||||
|
||||
return expected; |
||||
} |
||||
} |
@ -1,219 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.Recognizer; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.MurmurHash; |
||||
|
||||
/** A tuple: (ATN state, predicted alt, syntactic, semantic context). |
||||
* The syntactic context is a graph-structured stack node whose |
||||
* path(s) to the root is the rule invocation(s) |
||||
* chain used to arrive at the state. The semantic context is |
||||
* the tree of semantic predicates encountered before reaching |
||||
* an ATN state. |
||||
*/ |
||||
public class ATNConfig { |
||||
/** |
||||
* This field stores the bit mask for implementing the |
||||
* {@link #isPrecedenceFilterSuppressed} property as a bit within the |
||||
* existing {@link #reachesIntoOuterContext} field. |
||||
*/ |
||||
private static final int SUPPRESS_PRECEDENCE_FILTER = 0x40000000; |
||||
|
||||
/** The ATN state associated with this configuration */ |
||||
public final ATNState state; |
||||
|
||||
/** What alt (or lexer rule) is predicted by this configuration */ |
||||
public final int alt; |
||||
|
||||
/** The stack of invoking states leading to the rule/states associated |
||||
* with this config. We track only those contexts pushed during |
||||
* execution of the ATN simulator. |
||||
*/ |
||||
public PredictionContext context; |
||||
|
||||
/** |
||||
* We cannot execute predicates dependent upon local context unless |
||||
* we know for sure we are in the correct context. Because there is |
||||
* no way to do this efficiently, we simply cannot evaluate |
||||
* dependent predicates unless we are in the rule that initially |
||||
* invokes the ATN simulator. |
||||
* |
||||
* <p> |
||||
* closure() tracks the depth of how far we dip into the outer context: |
||||
* depth > 0. Note that it may not be totally accurate depth since I |
||||
* don't ever decrement. TODO: make it a boolean then</p> |
||||
* |
||||
* <p> |
||||
* For memory efficiency, the {@link #isPrecedenceFilterSuppressed} method |
||||
* is also backed by this field. Since the field is publicly accessible, the |
||||
* highest bit which would not cause the value to become negative is used to |
||||
* store this field. This choice minimizes the risk that code which only |
||||
* compares this value to 0 would be affected by the new purpose of the |
||||
* flag. It also ensures the performance of the existing {@link ATNConfig} |
||||
* constructors as well as certain operations like |
||||
* {@link ATNConfigSet#add(ATNConfig, DoubleKeyMap)} method are |
||||
* <em>completely</em> unaffected by the change.</p> |
||||
*/ |
||||
public int reachesIntoOuterContext; |
||||
|
||||
|
||||
public final SemanticContext semanticContext; |
||||
|
||||
public ATNConfig(ATNConfig old) { // dup
|
||||
this.state = old.state; |
||||
this.alt = old.alt; |
||||
this.context = old.context; |
||||
this.semanticContext = old.semanticContext; |
||||
this.reachesIntoOuterContext = old.reachesIntoOuterContext; |
||||
} |
||||
|
||||
public ATNConfig(ATNState state, |
||||
int alt, |
||||
PredictionContext context) |
||||
{ |
||||
this(state, alt, context, SemanticContext.NONE); |
||||
} |
||||
|
||||
public ATNConfig(ATNState state, |
||||
int alt, |
||||
PredictionContext context, |
||||
SemanticContext semanticContext) |
||||
{ |
||||
this.state = state; |
||||
this.alt = alt; |
||||
this.context = context; |
||||
this.semanticContext = semanticContext; |
||||
} |
||||
|
||||
public ATNConfig(ATNConfig c, ATNState state) { |
||||
this(c, state, c.context, c.semanticContext); |
||||
} |
||||
|
||||
public ATNConfig(ATNConfig c, ATNState state, |
||||
SemanticContext semanticContext) |
||||
{ |
||||
this(c, state, c.context, semanticContext); |
||||
} |
||||
|
||||
public ATNConfig(ATNConfig c, |
||||
SemanticContext semanticContext) |
||||
{ |
||||
this(c, c.state, c.context, semanticContext); |
||||
} |
||||
|
||||
public ATNConfig(ATNConfig c, ATNState state, |
||||
PredictionContext context) |
||||
{ |
||||
this(c, state, context, c.semanticContext); |
||||
} |
||||
|
||||
public ATNConfig(ATNConfig c, ATNState state, |
||||
PredictionContext context, |
||||
SemanticContext semanticContext) |
||||
{ |
||||
this.state = state; |
||||
this.alt = c.alt; |
||||
this.context = context; |
||||
this.semanticContext = semanticContext; |
||||
this.reachesIntoOuterContext = c.reachesIntoOuterContext; |
||||
} |
||||
|
||||
/** |
||||
* This method gets the value of the {@link #reachesIntoOuterContext} field |
||||
* as it existed prior to the introduction of the |
||||
* {@link #isPrecedenceFilterSuppressed} method. |
||||
*/ |
||||
public final int getOuterContextDepth() { |
||||
return reachesIntoOuterContext & ~SUPPRESS_PRECEDENCE_FILTER; |
||||
} |
||||
|
||||
public final boolean isPrecedenceFilterSuppressed() { |
||||
return (reachesIntoOuterContext & SUPPRESS_PRECEDENCE_FILTER) != 0; |
||||
} |
||||
|
||||
public final void setPrecedenceFilterSuppressed(boolean value) { |
||||
if (value) { |
||||
this.reachesIntoOuterContext |= 0x40000000; |
||||
} |
||||
else { |
||||
this.reachesIntoOuterContext &= ~SUPPRESS_PRECEDENCE_FILTER; |
||||
} |
||||
} |
||||
|
||||
/** An ATN configuration is equal to another if both have |
||||
* the same state, they predict the same alternative, and |
||||
* syntactic/semantic contexts are the same. |
||||
*/ |
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (!(o instanceof ATNConfig)) { |
||||
return false; |
||||
} |
||||
|
||||
return this.equals((ATNConfig)o); |
||||
} |
||||
|
||||
public boolean equals(ATNConfig other) { |
||||
if (this == other) { |
||||
return true; |
||||
} |
||||
else if (other == null) { |
||||
return false; |
||||
} |
||||
|
||||
return this.state.stateNumber==other.state.stateNumber |
||||
&& this.alt==other.alt |
||||
&& (this.context==other.context || (this.context != null && this.context.equals(other.context))) |
||||
&& this.semanticContext.equals(other.semanticContext) |
||||
&& this.isPrecedenceFilterSuppressed() == other.isPrecedenceFilterSuppressed(); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
int hashCode = MurmurHash.initialize(7); |
||||
hashCode = MurmurHash.update(hashCode, state.stateNumber); |
||||
hashCode = MurmurHash.update(hashCode, alt); |
||||
hashCode = MurmurHash.update(hashCode, context); |
||||
hashCode = MurmurHash.update(hashCode, semanticContext); |
||||
hashCode = MurmurHash.finish(hashCode, 4); |
||||
return hashCode; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return toString(null, true); |
||||
} |
||||
|
||||
public String toString(Recognizer<?, ?> recog, boolean showAlt) { |
||||
StringBuilder buf = new StringBuilder(); |
||||
// if ( state.ruleIndex>=0 ) {
|
||||
// if ( recog!=null ) buf.append(recog.getRuleNames()[state.ruleIndex]+":");
|
||||
// else buf.append(state.ruleIndex+":");
|
||||
// }
|
||||
buf.append('('); |
||||
buf.append(state); |
||||
if ( showAlt ) { |
||||
buf.append(","); |
||||
buf.append(alt); |
||||
} |
||||
if ( context!=null ) { |
||||
buf.append(",["); |
||||
buf.append(context.toString()); |
||||
buf.append("]"); |
||||
} |
||||
if ( semanticContext!=null && semanticContext != SemanticContext.NONE ) { |
||||
buf.append(","); |
||||
buf.append(semanticContext); |
||||
} |
||||
if ( getOuterContextDepth()>0 ) { |
||||
buf.append(",up=").append(getOuterContextDepth()); |
||||
} |
||||
buf.append(')'); |
||||
return buf.toString(); |
||||
} |
||||
} |
@ -1,387 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.AbstractEqualityComparator; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Array2DHashSet; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.DoubleKeyMap; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.BitSet; |
||||
import java.util.Collection; |
||||
import java.util.HashSet; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* Specialized {@link Set}{@code <}{@link ATNConfig}{@code >} that can track |
||||
* info about the set, with support for combining similar configurations using a |
||||
* graph-structured stack. |
||||
*/ |
||||
public class ATNConfigSet implements Set<ATNConfig> { |
||||
/** |
||||
* The reason that we need this is because we don't want the hash map to use |
||||
* the standard hash code and equals. We need all configurations with the same |
||||
* {@code (s,i,_,semctx)} to be equal. Unfortunately, this key effectively doubles |
||||
* the number of objects associated with ATNConfigs. The other solution is to |
||||
* use a hash table that lets us specify the equals/hashcode operation. |
||||
*/ |
||||
public static class ConfigHashSet extends AbstractConfigHashSet { |
||||
public ConfigHashSet() { |
||||
super(ConfigEqualityComparator.INSTANCE); |
||||
} |
||||
} |
||||
|
||||
public static final class ConfigEqualityComparator extends AbstractEqualityComparator<ATNConfig> { |
||||
public static final ConfigEqualityComparator INSTANCE = new ConfigEqualityComparator(); |
||||
|
||||
private ConfigEqualityComparator() { |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode(ATNConfig o) { |
||||
int hashCode = 7; |
||||
hashCode = 31 * hashCode + o.state.stateNumber; |
||||
hashCode = 31 * hashCode + o.alt; |
||||
hashCode = 31 * hashCode + o.semanticContext.hashCode(); |
||||
return hashCode; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(ATNConfig a, ATNConfig b) { |
||||
if ( a==b ) return true; |
||||
if ( a==null || b==null ) return false; |
||||
return a.state.stateNumber==b.state.stateNumber |
||||
&& a.alt==b.alt |
||||
&& a.semanticContext.equals(b.semanticContext); |
||||
} |
||||
} |
||||
|
||||
/** Indicates that the set of configurations is read-only. Do not |
||||
* allow any code to manipulate the set; DFA states will point at |
||||
* the sets and they must not change. This does not protect the other |
||||
* fields; in particular, conflictingAlts is set after |
||||
* we've made this readonly. |
||||
*/ |
||||
protected boolean readonly = false; |
||||
|
||||
/** |
||||
* All configs but hashed by (s, i, _, pi) not including context. Wiped out |
||||
* when we go readonly as this set becomes a DFA state. |
||||
*/ |
||||
public AbstractConfigHashSet configLookup; |
||||
|
||||
/** Track the elements as they are added to the set; supports get(i) */ |
||||
public final ArrayList<ATNConfig> configs = new ArrayList<ATNConfig>(7); |
||||
|
||||
// TODO: these fields make me pretty uncomfortable but nice to pack up info together, saves recomputation
|
||||
// TODO: can we track conflicts as they are added to save scanning configs later?
|
||||
public int uniqueAlt; |
||||
/** Currently this is only used when we detect SLL conflict; this does |
||||
* not necessarily represent the ambiguous alternatives. In fact, |
||||
* I should also point out that this seems to include predicated alternatives |
||||
* that have predicates that evaluate to false. Computed in computeTargetState(). |
||||
*/ |
||||
protected BitSet conflictingAlts; |
||||
|
||||
// Used in parser and lexer. In lexer, it indicates we hit a pred
|
||||
// while computing a closure operation. Don't make a DFA state from this.
|
||||
public boolean hasSemanticContext; |
||||
public boolean dipsIntoOuterContext; |
||||
|
||||
/** Indicates that this configuration set is part of a full context |
||||
* LL prediction. It will be used to determine how to merge $. With SLL |
||||
* it's a wildcard whereas it is not for LL context merge. |
||||
*/ |
||||
public final boolean fullCtx; |
||||
|
||||
private int cachedHashCode = -1; |
||||
|
||||
public ATNConfigSet(boolean fullCtx) { |
||||
configLookup = new ConfigHashSet(); |
||||
this.fullCtx = fullCtx; |
||||
} |
||||
public ATNConfigSet() { this(true); } |
||||
|
||||
public ATNConfigSet(ATNConfigSet old) { |
||||
this(old.fullCtx); |
||||
addAll(old); |
||||
this.uniqueAlt = old.uniqueAlt; |
||||
this.conflictingAlts = old.conflictingAlts; |
||||
this.hasSemanticContext = old.hasSemanticContext; |
||||
this.dipsIntoOuterContext = old.dipsIntoOuterContext; |
||||
} |
||||
|
||||
@Override |
||||
public boolean add(ATNConfig config) { |
||||
return add(config, null); |
||||
} |
||||
|
||||
/** |
||||
* Adding a new config means merging contexts with existing configs for |
||||
* {@code (s, i, pi, _)}, where {@code s} is the |
||||
* {@link ATNConfig#state}, {@code i} is the {@link ATNConfig#alt}, and |
||||
* {@code pi} is the {@link ATNConfig#semanticContext}. We use |
||||
* {@code (s,i,pi)} as key. |
||||
* |
||||
* <p>This method updates {@link #dipsIntoOuterContext} and |
||||
* {@link #hasSemanticContext} when necessary.</p> |
||||
*/ |
||||
public boolean add( |
||||
ATNConfig config, |
||||
DoubleKeyMap<PredictionContext,PredictionContext,PredictionContext> mergeCache) |
||||
{ |
||||
if ( readonly ) throw new IllegalStateException("This set is readonly"); |
||||
if ( config.semanticContext!=SemanticContext.NONE ) { |
||||
hasSemanticContext = true; |
||||
} |
||||
if (config.getOuterContextDepth() > 0) { |
||||
dipsIntoOuterContext = true; |
||||
} |
||||
ATNConfig existing = configLookup.getOrAdd(config); |
||||
if ( existing==config ) { // we added this new one
|
||||
cachedHashCode = -1; |
||||
configs.add(config); // track order here
|
||||
return true; |
||||
} |
||||
// a previous (s,i,pi,_), merge with it and save result
|
||||
boolean rootIsWildcard = !fullCtx; |
||||
PredictionContext merged = |
||||
PredictionContext.merge(existing.context, config.context, rootIsWildcard, mergeCache); |
||||
// no need to check for existing.context, config.context in cache
|
||||
// since only way to create new graphs is "call rule" and here. We
|
||||
// cache at both places.
|
||||
existing.reachesIntoOuterContext = |
||||
Math.max(existing.reachesIntoOuterContext, config.reachesIntoOuterContext); |
||||
|
||||
// make sure to preserve the precedence filter suppression during the merge
|
||||
if (config.isPrecedenceFilterSuppressed()) { |
||||
existing.setPrecedenceFilterSuppressed(true); |
||||
} |
||||
|
||||
existing.context = merged; // replace context; no need to alt mapping
|
||||
return true; |
||||
} |
||||
|
||||
/** Return a List holding list of configs */ |
||||
public List<ATNConfig> elements() { return configs; } |
||||
|
||||
public Set<ATNState> getStates() { |
||||
Set<ATNState> states = new HashSet<ATNState>(); |
||||
for (ATNConfig c : configs) { |
||||
states.add(c.state); |
||||
} |
||||
return states; |
||||
} |
||||
|
||||
/** |
||||
* Gets the complete set of represented alternatives for the configuration |
||||
* set. |
||||
* |
||||
* @return the set of represented alternatives in this configuration set |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
|
||||
public BitSet getAlts() { |
||||
BitSet alts = new BitSet(); |
||||
for (ATNConfig config : configs) { |
||||
alts.set(config.alt); |
||||
} |
||||
return alts; |
||||
} |
||||
|
||||
public List<SemanticContext> getPredicates() { |
||||
List<SemanticContext> preds = new ArrayList<SemanticContext>(); |
||||
for (ATNConfig c : configs) { |
||||
if ( c.semanticContext!=SemanticContext.NONE ) { |
||||
preds.add(c.semanticContext); |
||||
} |
||||
} |
||||
return preds; |
||||
} |
||||
|
||||
public ATNConfig get(int i) { return configs.get(i); } |
||||
|
||||
public void optimizeConfigs(ATNSimulator interpreter) { |
||||
if ( readonly ) throw new IllegalStateException("This set is readonly"); |
||||
if ( configLookup.isEmpty() ) return; |
||||
|
||||
for (ATNConfig config : configs) { |
||||
// int before = PredictionContext.getAllContextNodes(config.context).size();
|
||||
config.context = interpreter.getCachedContext(config.context); |
||||
// int after = PredictionContext.getAllContextNodes(config.context).size();
|
||||
// System.out.println("configs "+before+"->"+after);
|
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(Collection<? extends ATNConfig> coll) { |
||||
for (ATNConfig c : coll) add(c); |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (o == this) { |
||||
return true; |
||||
} |
||||
else if (!(o instanceof ATNConfigSet)) { |
||||
return false; |
||||
} |
||||
|
||||
// System.out.print("equals " + this + ", " + o+" = ");
|
||||
ATNConfigSet other = (ATNConfigSet)o; |
||||
boolean same = configs!=null && |
||||
configs.equals(other.configs) && // includes stack context
|
||||
this.fullCtx == other.fullCtx && |
||||
this.uniqueAlt == other.uniqueAlt && |
||||
this.conflictingAlts == other.conflictingAlts && |
||||
this.hasSemanticContext == other.hasSemanticContext && |
||||
this.dipsIntoOuterContext == other.dipsIntoOuterContext; |
||||
|
||||
// System.out.println(same);
|
||||
return same; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
if (isReadonly()) { |
||||
if (cachedHashCode == -1) { |
||||
cachedHashCode = configs.hashCode(); |
||||
} |
||||
|
||||
return cachedHashCode; |
||||
} |
||||
|
||||
return configs.hashCode(); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return configs.size(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
return configs.isEmpty(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean contains(Object o) { |
||||
if (configLookup == null) { |
||||
throw new UnsupportedOperationException("This method is not implemented for readonly sets."); |
||||
} |
||||
|
||||
return configLookup.contains(o); |
||||
} |
||||
|
||||
public boolean containsFast(ATNConfig obj) { |
||||
if (configLookup == null) { |
||||
throw new UnsupportedOperationException("This method is not implemented for readonly sets."); |
||||
} |
||||
|
||||
return configLookup.containsFast(obj); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<ATNConfig> iterator() { |
||||
return configs.iterator(); |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
if ( readonly ) throw new IllegalStateException("This set is readonly"); |
||||
configs.clear(); |
||||
cachedHashCode = -1; |
||||
configLookup.clear(); |
||||
} |
||||
|
||||
public boolean isReadonly() { |
||||
return readonly; |
||||
} |
||||
|
||||
public void setReadonly(boolean readonly) { |
||||
this.readonly = readonly; |
||||
configLookup = null; // can't mod, no need for lookup cache
|
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
StringBuilder buf = new StringBuilder(); |
||||
buf.append(elements().toString()); |
||||
if ( hasSemanticContext ) buf.append(",hasSemanticContext=").append(hasSemanticContext); |
||||
if ( uniqueAlt!=ATN.INVALID_ALT_NUMBER ) buf.append(",uniqueAlt=").append(uniqueAlt); |
||||
if ( conflictingAlts!=null ) buf.append(",conflictingAlts=").append(conflictingAlts); |
||||
if ( dipsIntoOuterContext ) buf.append(",dipsIntoOuterContext"); |
||||
return buf.toString(); |
||||
} |
||||
|
||||
// satisfy interface
|
||||
|
||||
@Override |
||||
public ATNConfig[] toArray() { |
||||
return configLookup.toArray(); |
||||
} |
||||
|
||||
@Override |
||||
public <T> T[] toArray(T[] a) { |
||||
return configLookup.toArray(a); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(Object o) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsAll(Collection<?> c) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean retainAll(Collection<?> c) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(Collection<?> c) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
public static abstract class AbstractConfigHashSet extends Array2DHashSet<ATNConfig> { |
||||
|
||||
public AbstractConfigHashSet(AbstractEqualityComparator<? super ATNConfig> comparator) { |
||||
this(comparator, 16, 2); |
||||
} |
||||
|
||||
public AbstractConfigHashSet(AbstractEqualityComparator<? super ATNConfig> comparator, int initialCapacity, int initialBucketCapacity) { |
||||
super(comparator, initialCapacity, initialBucketCapacity); |
||||
} |
||||
|
||||
@Override |
||||
protected final ATNConfig asElementType(Object o) { |
||||
if (!(o instanceof ATNConfig)) { |
||||
return null; |
||||
} |
||||
|
||||
return (ATNConfig)o; |
||||
} |
||||
|
||||
@Override |
||||
protected final ATNConfig[][] createBuckets(int capacity) { |
||||
return new ATNConfig[capacity][]; |
||||
} |
||||
|
||||
@Override |
||||
protected final ATNConfig[] createBucket(int capacity) { |
||||
return new ATNConfig[capacity]; |
||||
} |
||||
|
||||
} |
||||
} |
@ -1,70 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
/** |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public class ATNDeserializationOptions { |
||||
private static final ATNDeserializationOptions defaultOptions; |
||||
static { |
||||
defaultOptions = new ATNDeserializationOptions(); |
||||
defaultOptions.makeReadOnly(); |
||||
} |
||||
|
||||
private boolean readOnly; |
||||
private boolean verifyATN; |
||||
private boolean generateRuleBypassTransitions; |
||||
|
||||
public ATNDeserializationOptions() { |
||||
this.verifyATN = true; |
||||
this.generateRuleBypassTransitions = false; |
||||
} |
||||
|
||||
public ATNDeserializationOptions(ATNDeserializationOptions options) { |
||||
this.verifyATN = options.verifyATN; |
||||
this.generateRuleBypassTransitions = options.generateRuleBypassTransitions; |
||||
} |
||||
|
||||
|
||||
public static ATNDeserializationOptions getDefaultOptions() { |
||||
return defaultOptions; |
||||
} |
||||
|
||||
public final boolean isReadOnly() { |
||||
return readOnly; |
||||
} |
||||
|
||||
public final void makeReadOnly() { |
||||
readOnly = true; |
||||
} |
||||
|
||||
public final boolean isVerifyATN() { |
||||
return verifyATN; |
||||
} |
||||
|
||||
public final void setVerifyATN(boolean verifyATN) { |
||||
throwIfReadOnly(); |
||||
this.verifyATN = verifyATN; |
||||
} |
||||
|
||||
public final boolean isGenerateRuleBypassTransitions() { |
||||
return generateRuleBypassTransitions; |
||||
} |
||||
|
||||
public final void setGenerateRuleBypassTransitions(boolean generateRuleBypassTransitions) { |
||||
throwIfReadOnly(); |
||||
this.generateRuleBypassTransitions = generateRuleBypassTransitions; |
||||
} |
||||
|
||||
protected void throwIfReadOnly() { |
||||
if (isReadOnly()) { |
||||
throw new IllegalStateException("The object is read only."); |
||||
} |
||||
} |
||||
} |
@ -1,796 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.Token; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntervalSet; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Pair; |
||||
|
||||
import java.io.InvalidClassException; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Locale; |
||||
import java.util.UUID; |
||||
|
||||
/** |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public class ATNDeserializer { |
||||
public static final int SERIALIZED_VERSION; |
||||
static { |
||||
/* This value should never change. Updates following this version are |
||||
* reflected as change in the unique ID SERIALIZED_UUID. |
||||
*/ |
||||
SERIALIZED_VERSION = 3; |
||||
} |
||||
|
||||
/** |
||||
* This is the earliest supported serialized UUID. |
||||
*/ |
||||
private static final UUID BASE_SERIALIZED_UUID; |
||||
/** |
||||
* This UUID indicates an extension of {@link BASE_SERIALIZED_UUID} for the |
||||
* addition of precedence predicates. |
||||
*/ |
||||
private static final UUID ADDED_PRECEDENCE_TRANSITIONS; |
||||
/** |
||||
* This UUID indicates an extension of {@link #ADDED_PRECEDENCE_TRANSITIONS} |
||||
* for the addition of lexer actions encoded as a sequence of |
||||
* {@link LexerAction} instances. |
||||
*/ |
||||
private static final UUID ADDED_LEXER_ACTIONS; |
||||
/** |
||||
* This UUID indicates the serialized ATN contains two sets of |
||||
* IntervalSets, where the second set's values are encoded as |
||||
* 32-bit integers to support the full Unicode SMP range up to U+10FFFF. |
||||
*/ |
||||
private static final UUID ADDED_UNICODE_SMP; |
||||
/** |
||||
* This list contains all of the currently supported UUIDs, ordered by when |
||||
* the feature first appeared in this branch. |
||||
*/ |
||||
private static final List<UUID> SUPPORTED_UUIDS; |
||||
|
||||
/** |
||||
* This is the current serialized UUID. |
||||
*/ |
||||
public static final UUID SERIALIZED_UUID; |
||||
static { |
||||
/* WARNING: DO NOT MERGE THESE LINES. If UUIDs differ during a merge, |
||||
* resolve the conflict by generating a new ID! |
||||
*/ |
||||
BASE_SERIALIZED_UUID = UUID.fromString("33761B2D-78BB-4A43-8B0B-4F5BEE8AACF3"); |
||||
ADDED_PRECEDENCE_TRANSITIONS = UUID.fromString("1DA0C57D-6C06-438A-9B27-10BCB3CE0F61"); |
||||
ADDED_LEXER_ACTIONS = UUID.fromString("AADB8D7E-AEEF-4415-AD2B-8204D6CF042E"); |
||||
ADDED_UNICODE_SMP = UUID.fromString("59627784-3BE5-417A-B9EB-8131A7286089"); |
||||
|
||||
SUPPORTED_UUIDS = new ArrayList<UUID>(); |
||||
SUPPORTED_UUIDS.add(BASE_SERIALIZED_UUID); |
||||
SUPPORTED_UUIDS.add(ADDED_PRECEDENCE_TRANSITIONS); |
||||
SUPPORTED_UUIDS.add(ADDED_LEXER_ACTIONS); |
||||
SUPPORTED_UUIDS.add(ADDED_UNICODE_SMP); |
||||
|
||||
SERIALIZED_UUID = ADDED_UNICODE_SMP; |
||||
} |
||||
|
||||
interface UnicodeDeserializer { |
||||
// Wrapper for readInt() or readInt32()
|
||||
int readUnicode(char[] data, int p); |
||||
|
||||
// Work around Java not allowing mutation of captured variables
|
||||
// by returning amount by which to increment p after each read
|
||||
int size(); |
||||
} |
||||
|
||||
enum UnicodeDeserializingMode { |
||||
UNICODE_BMP, |
||||
UNICODE_SMP |
||||
} |
||||
|
||||
static UnicodeDeserializer getUnicodeDeserializer(UnicodeDeserializingMode mode) { |
||||
if (mode == UnicodeDeserializingMode.UNICODE_BMP) { |
||||
return new UnicodeDeserializer() { |
||||
@Override |
||||
public int readUnicode(char[] data, int p) { |
||||
return toInt(data[p]); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return 1; |
||||
} |
||||
}; |
||||
} |
||||
else { |
||||
return new UnicodeDeserializer() { |
||||
@Override |
||||
public int readUnicode(char[] data, int p) { |
||||
return toInt32(data, p); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return 2; |
||||
} |
||||
}; |
||||
} |
||||
} |
||||
|
||||
private final ATNDeserializationOptions deserializationOptions; |
||||
|
||||
public ATNDeserializer() { |
||||
this(ATNDeserializationOptions.getDefaultOptions()); |
||||
} |
||||
|
||||
public ATNDeserializer(ATNDeserializationOptions deserializationOptions) { |
||||
if (deserializationOptions == null) { |
||||
deserializationOptions = ATNDeserializationOptions.getDefaultOptions(); |
||||
} |
||||
|
||||
this.deserializationOptions = deserializationOptions; |
||||
} |
||||
|
||||
/** |
||||
* Determines if a particular serialized representation of an ATN supports |
||||
* a particular feature, identified by the {@link UUID} used for serializing |
||||
* the ATN at the time the feature was first introduced. |
||||
* |
||||
* @param feature The {@link UUID} marking the first time the feature was |
||||
* supported in the serialized ATN. |
||||
* @param actualUuid The {@link UUID} of the actual serialized ATN which is |
||||
* currently being deserialized. |
||||
* @return {@code true} if the {@code actualUuid} value represents a |
||||
* serialized ATN at or after the feature identified by {@code feature} was |
||||
* introduced; otherwise, {@code false}. |
||||
*/ |
||||
static protected boolean isFeatureSupported(UUID feature, UUID actualUuid) { |
||||
int featureIndex = SUPPORTED_UUIDS.indexOf(feature); |
||||
if (featureIndex < 0) { |
||||
return false; |
||||
} |
||||
|
||||
return SUPPORTED_UUIDS.indexOf(actualUuid) >= featureIndex; |
||||
} |
||||
|
||||
@SuppressWarnings("deprecation") |
||||
public ATN deserialize(char[] data) { |
||||
data = data.clone(); |
||||
|
||||
// Each char value in data is shifted by +2 at the entry to this method.
|
||||
// This is an encoding optimization targeting the serialized values 0
|
||||
// and -1 (serialized to 0xFFFF), each of which are very common in the
|
||||
// serialized form of the ATN. In the modified UTF-8 that Java uses for
|
||||
// compiled string literals, these two character values have multi-byte
|
||||
// forms. By shifting each value by +2, they become characters 2 and 1
|
||||
// prior to writing the string, each of which have single-byte
|
||||
// representations. Since the shift occurs in the tool during ATN
|
||||
// serialization, each target is responsible for adjusting the values
|
||||
// during deserialization.
|
||||
//
|
||||
// As a special case, note that the first element of data is not
|
||||
// adjusted because it contains the major version number of the
|
||||
// serialized ATN, which was fixed at 3 at the time the value shifting
|
||||
// was implemented.
|
||||
for (int i = 1; i < data.length; i++) { |
||||
data[i] = (char)(data[i] - 2); |
||||
} |
||||
|
||||
int p = 0; |
||||
int version = toInt(data[p++]); |
||||
if (version != SERIALIZED_VERSION) { |
||||
String reason = String.format(Locale.getDefault(), "Could not deserialize ATN with version %d (expected %d).", version, SERIALIZED_VERSION); |
||||
throw new UnsupportedOperationException(new InvalidClassException(ATN.class.getName(), reason)); |
||||
} |
||||
|
||||
UUID uuid = toUUID(data, p); |
||||
p += 8; |
||||
if (!SUPPORTED_UUIDS.contains(uuid)) { |
||||
String reason = String.format(Locale.getDefault(), "Could not deserialize ATN with UUID %s (expected %s or a legacy UUID).", uuid, SERIALIZED_UUID); |
||||
throw new UnsupportedOperationException(new InvalidClassException(ATN.class.getName(), reason)); |
||||
} |
||||
|
||||
boolean supportsPrecedencePredicates = isFeatureSupported(ADDED_PRECEDENCE_TRANSITIONS, uuid); |
||||
boolean supportsLexerActions = isFeatureSupported(ADDED_LEXER_ACTIONS, uuid); |
||||
|
||||
ATNType grammarType = ATNType.values()[toInt(data[p++])]; |
||||
int maxTokenType = toInt(data[p++]); |
||||
ATN atn = new ATN(grammarType, maxTokenType); |
||||
|
||||
//
|
||||
// STATES
|
||||
//
|
||||
List<Pair<LoopEndState, Integer>> loopBackStateNumbers = new ArrayList<Pair<LoopEndState, Integer>>(); |
||||
List<Pair<BlockStartState, Integer>> endStateNumbers = new ArrayList<Pair<BlockStartState, Integer>>(); |
||||
int nstates = toInt(data[p++]); |
||||
for (int i=0; i<nstates; i++) { |
||||
int stype = toInt(data[p++]); |
||||
// ignore bad type of states
|
||||
if ( stype==ATNState.INVALID_TYPE ) { |
||||
atn.addState(null); |
||||
continue; |
||||
} |
||||
|
||||
int ruleIndex = toInt(data[p++]); |
||||
if (ruleIndex == Character.MAX_VALUE) { |
||||
ruleIndex = -1; |
||||
} |
||||
|
||||
ATNState s = stateFactory(stype, ruleIndex); |
||||
if ( stype == ATNState.LOOP_END ) { // special case
|
||||
int loopBackStateNumber = toInt(data[p++]); |
||||
loopBackStateNumbers.add(new Pair<LoopEndState, Integer>((LoopEndState)s, loopBackStateNumber)); |
||||
} |
||||
else if (s instanceof BlockStartState) { |
||||
int endStateNumber = toInt(data[p++]); |
||||
endStateNumbers.add(new Pair<BlockStartState, Integer>((BlockStartState)s, endStateNumber)); |
||||
} |
||||
atn.addState(s); |
||||
} |
||||
|
||||
// delay the assignment of loop back and end states until we know all the state instances have been initialized
|
||||
for (Pair<LoopEndState, Integer> pair : loopBackStateNumbers) { |
||||
pair.a.loopBackState = atn.states.get(pair.b); |
||||
} |
||||
|
||||
for (Pair<BlockStartState, Integer> pair : endStateNumbers) { |
||||
pair.a.endState = (BlockEndState)atn.states.get(pair.b); |
||||
} |
||||
|
||||
int numNonGreedyStates = toInt(data[p++]); |
||||
for (int i = 0; i < numNonGreedyStates; i++) { |
||||
int stateNumber = toInt(data[p++]); |
||||
((DecisionState)atn.states.get(stateNumber)).nonGreedy = true; |
||||
} |
||||
|
||||
if (supportsPrecedencePredicates) { |
||||
int numPrecedenceStates = toInt(data[p++]); |
||||
for (int i = 0; i < numPrecedenceStates; i++) { |
||||
int stateNumber = toInt(data[p++]); |
||||
((RuleStartState)atn.states.get(stateNumber)).isLeftRecursiveRule = true; |
||||
} |
||||
} |
||||
|
||||
//
|
||||
// RULES
|
||||
//
|
||||
int nrules = toInt(data[p++]); |
||||
if ( atn.grammarType == ATNType.LEXER ) { |
||||
atn.ruleToTokenType = new int[nrules]; |
||||
} |
||||
|
||||
atn.ruleToStartState = new RuleStartState[nrules]; |
||||
for (int i=0; i<nrules; i++) { |
||||
int s = toInt(data[p++]); |
||||
RuleStartState startState = (RuleStartState)atn.states.get(s); |
||||
atn.ruleToStartState[i] = startState; |
||||
if ( atn.grammarType == ATNType.LEXER ) { |
||||
int tokenType = toInt(data[p++]); |
||||
if (tokenType == 0xFFFF) { |
||||
tokenType = Token.EOF; |
||||
} |
||||
|
||||
atn.ruleToTokenType[i] = tokenType; |
||||
|
||||
if (!isFeatureSupported(ADDED_LEXER_ACTIONS, uuid)) { |
||||
// this piece of unused metadata was serialized prior to the
|
||||
// addition of LexerAction
|
||||
int actionIndexIgnored = toInt(data[p++]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
atn.ruleToStopState = new RuleStopState[nrules]; |
||||
for (ATNState state : atn.states) { |
||||
if (!(state instanceof RuleStopState)) { |
||||
continue; |
||||
} |
||||
|
||||
RuleStopState stopState = (RuleStopState)state; |
||||
atn.ruleToStopState[state.ruleIndex] = stopState; |
||||
atn.ruleToStartState[state.ruleIndex].stopState = stopState; |
||||
} |
||||
|
||||
//
|
||||
// MODES
|
||||
//
|
||||
int nmodes = toInt(data[p++]); |
||||
for (int i=0; i<nmodes; i++) { |
||||
int s = toInt(data[p++]); |
||||
atn.modeToStartState.add((TokensStartState)atn.states.get(s)); |
||||
} |
||||
|
||||
//
|
||||
// SETS
|
||||
//
|
||||
List<IntervalSet> sets = new ArrayList<IntervalSet>(); |
||||
|
||||
// First, read all sets with 16-bit Unicode code points <= U+FFFF.
|
||||
p = deserializeSets(data, p, sets, getUnicodeDeserializer(UnicodeDeserializingMode.UNICODE_BMP)); |
||||
|
||||
// Next, if the ATN was serialized with the Unicode SMP feature,
|
||||
// deserialize sets with 32-bit arguments <= U+10FFFF.
|
||||
if (isFeatureSupported(ADDED_UNICODE_SMP, uuid)) { |
||||
p = deserializeSets(data, p, sets, getUnicodeDeserializer(UnicodeDeserializingMode.UNICODE_SMP)); |
||||
} |
||||
|
||||
//
|
||||
// EDGES
|
||||
//
|
||||
int nedges = toInt(data[p++]); |
||||
for (int i=0; i<nedges; i++) { |
||||
int src = toInt(data[p]); |
||||
int trg = toInt(data[p+1]); |
||||
int ttype = toInt(data[p+2]); |
||||
int arg1 = toInt(data[p+3]); |
||||
int arg2 = toInt(data[p+4]); |
||||
int arg3 = toInt(data[p+5]); |
||||
Transition trans = edgeFactory(atn, ttype, src, trg, arg1, arg2, arg3, sets); |
||||
// System.out.println("EDGE "+trans.getClass().getSimpleName()+" "+
|
||||
// src+"->"+trg+
|
||||
// " "+Transition.serializationNames[ttype]+
|
||||
// " "+arg1+","+arg2+","+arg3);
|
||||
ATNState srcState = atn.states.get(src); |
||||
srcState.addTransition(trans); |
||||
p += 6; |
||||
} |
||||
|
||||
// edges for rule stop states can be derived, so they aren't serialized
|
||||
for (ATNState state : atn.states) { |
||||
for (int i = 0; i < state.getNumberOfTransitions(); i++) { |
||||
Transition t = state.transition(i); |
||||
if (!(t instanceof RuleTransition)) { |
||||
continue; |
||||
} |
||||
|
||||
RuleTransition ruleTransition = (RuleTransition)t; |
||||
int outermostPrecedenceReturn = -1; |
||||
if (atn.ruleToStartState[ruleTransition.target.ruleIndex].isLeftRecursiveRule) { |
||||
if (ruleTransition.precedence == 0) { |
||||
outermostPrecedenceReturn = ruleTransition.target.ruleIndex; |
||||
} |
||||
} |
||||
|
||||
EpsilonTransition returnTransition = new EpsilonTransition(ruleTransition.followState, outermostPrecedenceReturn); |
||||
atn.ruleToStopState[ruleTransition.target.ruleIndex].addTransition(returnTransition); |
||||
} |
||||
} |
||||
|
||||
for (ATNState state : atn.states) { |
||||
if (state instanceof BlockStartState) { |
||||
// we need to know the end state to set its start state
|
||||
if (((BlockStartState)state).endState == null) { |
||||
throw new IllegalStateException(); |
||||
} |
||||
|
||||
// block end states can only be associated to a single block start state
|
||||
if (((BlockStartState)state).endState.startState != null) { |
||||
throw new IllegalStateException(); |
||||
} |
||||
|
||||
((BlockStartState)state).endState.startState = (BlockStartState)state; |
||||
} |
||||
|
||||
if (state instanceof PlusLoopbackState) { |
||||
PlusLoopbackState loopbackState = (PlusLoopbackState)state; |
||||
for (int i = 0; i < loopbackState.getNumberOfTransitions(); i++) { |
||||
ATNState target = loopbackState.transition(i).target; |
||||
if (target instanceof PlusBlockStartState) { |
||||
((PlusBlockStartState)target).loopBackState = loopbackState; |
||||
} |
||||
} |
||||
} |
||||
else if (state instanceof StarLoopbackState) { |
||||
StarLoopbackState loopbackState = (StarLoopbackState)state; |
||||
for (int i = 0; i < loopbackState.getNumberOfTransitions(); i++) { |
||||
ATNState target = loopbackState.transition(i).target; |
||||
if (target instanceof StarLoopEntryState) { |
||||
((StarLoopEntryState)target).loopBackState = loopbackState; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
//
|
||||
// DECISIONS
|
||||
//
|
||||
int ndecisions = toInt(data[p++]); |
||||
for (int i=1; i<=ndecisions; i++) { |
||||
int s = toInt(data[p++]); |
||||
DecisionState decState = (DecisionState)atn.states.get(s); |
||||
atn.decisionToState.add(decState); |
||||
decState.decision = i-1; |
||||
} |
||||
|
||||
//
|
||||
// LEXER ACTIONS
|
||||
//
|
||||
if (atn.grammarType == ATNType.LEXER) { |
||||
if (supportsLexerActions) { |
||||
atn.lexerActions = new LexerAction[toInt(data[p++])]; |
||||
for (int i = 0; i < atn.lexerActions.length; i++) { |
||||
LexerActionType actionType = LexerActionType.values()[toInt(data[p++])]; |
||||
int data1 = toInt(data[p++]); |
||||
if (data1 == 0xFFFF) { |
||||
data1 = -1; |
||||
} |
||||
|
||||
int data2 = toInt(data[p++]); |
||||
if (data2 == 0xFFFF) { |
||||
data2 = -1; |
||||
} |
||||
|
||||
LexerAction lexerAction = lexerActionFactory(actionType, data1, data2); |
||||
|
||||
atn.lexerActions[i] = lexerAction; |
||||
} |
||||
} |
||||
else { |
||||
// for compatibility with older serialized ATNs, convert the old
|
||||
// serialized action index for action transitions to the new
|
||||
// form, which is the index of a LexerCustomAction
|
||||
List<LexerAction> legacyLexerActions = new ArrayList<LexerAction>(); |
||||
for (ATNState state : atn.states) { |
||||
for (int i = 0; i < state.getNumberOfTransitions(); i++) { |
||||
Transition transition = state.transition(i); |
||||
if (!(transition instanceof ActionTransition)) { |
||||
continue; |
||||
} |
||||
|
||||
int ruleIndex = ((ActionTransition)transition).ruleIndex; |
||||
int actionIndex = ((ActionTransition)transition).actionIndex; |
||||
LexerCustomAction lexerAction = new LexerCustomAction(ruleIndex, actionIndex); |
||||
state.setTransition(i, new ActionTransition(transition.target, ruleIndex, legacyLexerActions.size(), false)); |
||||
legacyLexerActions.add(lexerAction); |
||||
} |
||||
} |
||||
|
||||
atn.lexerActions = legacyLexerActions.toArray(new LexerAction[legacyLexerActions.size()]); |
||||
} |
||||
} |
||||
|
||||
markPrecedenceDecisions(atn); |
||||
|
||||
if (deserializationOptions.isVerifyATN()) { |
||||
verifyATN(atn); |
||||
} |
||||
|
||||
if (deserializationOptions.isGenerateRuleBypassTransitions() && atn.grammarType == ATNType.PARSER) { |
||||
atn.ruleToTokenType = new int[atn.ruleToStartState.length]; |
||||
for (int i = 0; i < atn.ruleToStartState.length; i++) { |
||||
atn.ruleToTokenType[i] = atn.maxTokenType + i + 1; |
||||
} |
||||
|
||||
for (int i = 0; i < atn.ruleToStartState.length; i++) { |
||||
BasicBlockStartState bypassStart = new BasicBlockStartState(); |
||||
bypassStart.ruleIndex = i; |
||||
atn.addState(bypassStart); |
||||
|
||||
BlockEndState bypassStop = new BlockEndState(); |
||||
bypassStop.ruleIndex = i; |
||||
atn.addState(bypassStop); |
||||
|
||||
bypassStart.endState = bypassStop; |
||||
atn.defineDecisionState(bypassStart); |
||||
|
||||
bypassStop.startState = bypassStart; |
||||
|
||||
ATNState endState; |
||||
Transition excludeTransition = null; |
||||
if (atn.ruleToStartState[i].isLeftRecursiveRule) { |
||||
// wrap from the beginning of the rule to the StarLoopEntryState
|
||||
endState = null; |
||||
for (ATNState state : atn.states) { |
||||
if (state.ruleIndex != i) { |
||||
continue; |
||||
} |
||||
|
||||
if (!(state instanceof StarLoopEntryState)) { |
||||
continue; |
||||
} |
||||
|
||||
ATNState maybeLoopEndState = state.transition(state.getNumberOfTransitions() - 1).target; |
||||
if (!(maybeLoopEndState instanceof LoopEndState)) { |
||||
continue; |
||||
} |
||||
|
||||
if (maybeLoopEndState.epsilonOnlyTransitions && maybeLoopEndState.transition(0).target instanceof RuleStopState) { |
||||
endState = state; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (endState == null) { |
||||
throw new UnsupportedOperationException("Couldn't identify final state of the precedence rule prefix section."); |
||||
} |
||||
|
||||
excludeTransition = ((StarLoopEntryState)endState).loopBackState.transition(0); |
||||
} |
||||
else { |
||||
endState = atn.ruleToStopState[i]; |
||||
} |
||||
|
||||
// all non-excluded transitions that currently target end state need to target blockEnd instead
|
||||
for (ATNState state : atn.states) { |
||||
for (Transition transition : state.transitions) { |
||||
if (transition == excludeTransition) { |
||||
continue; |
||||
} |
||||
|
||||
if (transition.target == endState) { |
||||
transition.target = bypassStop; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// all transitions leaving the rule start state need to leave blockStart instead
|
||||
while (atn.ruleToStartState[i].getNumberOfTransitions() > 0) { |
||||
Transition transition = atn.ruleToStartState[i].removeTransition(atn.ruleToStartState[i].getNumberOfTransitions() - 1); |
||||
bypassStart.addTransition(transition); |
||||
} |
||||
|
||||
// link the new states
|
||||
atn.ruleToStartState[i].addTransition(new EpsilonTransition(bypassStart)); |
||||
bypassStop.addTransition(new EpsilonTransition(endState)); |
||||
|
||||
ATNState matchState = new BasicState(); |
||||
atn.addState(matchState); |
||||
matchState.addTransition(new AtomTransition(bypassStop, atn.ruleToTokenType[i])); |
||||
bypassStart.addTransition(new EpsilonTransition(matchState)); |
||||
} |
||||
|
||||
if (deserializationOptions.isVerifyATN()) { |
||||
// reverify after modification
|
||||
verifyATN(atn); |
||||
} |
||||
} |
||||
|
||||
return atn; |
||||
} |
||||
|
||||
private int deserializeSets(char[] data, int p, List<IntervalSet> sets, UnicodeDeserializer unicodeDeserializer) { |
||||
int nsets = toInt(data[p++]); |
||||
for (int i=0; i<nsets; i++) { |
||||
int nintervals = toInt(data[p]); |
||||
p++; |
||||
IntervalSet set = new IntervalSet(); |
||||
sets.add(set); |
||||
|
||||
boolean containsEof = toInt(data[p++]) != 0; |
||||
if (containsEof) { |
||||
set.add(-1); |
||||
} |
||||
|
||||
for (int j=0; j<nintervals; j++) { |
||||
int a = unicodeDeserializer.readUnicode(data, p); |
||||
p += unicodeDeserializer.size(); |
||||
int b = unicodeDeserializer.readUnicode(data, p); |
||||
p += unicodeDeserializer.size(); |
||||
set.add(a, b); |
||||
} |
||||
} |
||||
return p; |
||||
} |
||||
|
||||
/** |
||||
* Analyze the {@link StarLoopEntryState} states in the specified ATN to set |
||||
* the {@link StarLoopEntryState#isPrecedenceDecision} field to the |
||||
* correct value. |
||||
* |
||||
* @param atn The ATN. |
||||
*/ |
||||
protected void markPrecedenceDecisions(ATN atn) { |
||||
for (ATNState state : atn.states) { |
||||
if (!(state instanceof StarLoopEntryState)) { |
||||
continue; |
||||
} |
||||
|
||||
/* We analyze the ATN to determine if this ATN decision state is the |
||||
* decision for the closure block that determines whether a |
||||
* precedence rule should continue or complete. |
||||
*/ |
||||
if (atn.ruleToStartState[state.ruleIndex].isLeftRecursiveRule) { |
||||
ATNState maybeLoopEndState = state.transition(state.getNumberOfTransitions() - 1).target; |
||||
if (maybeLoopEndState instanceof LoopEndState) { |
||||
if (maybeLoopEndState.epsilonOnlyTransitions && maybeLoopEndState.transition(0).target instanceof RuleStopState) { |
||||
((StarLoopEntryState)state).isPrecedenceDecision = true; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected void verifyATN(ATN atn) { |
||||
// verify assumptions
|
||||
for (ATNState state : atn.states) { |
||||
if (state == null) { |
||||
continue; |
||||
} |
||||
|
||||
checkCondition(state.onlyHasEpsilonTransitions() || state.getNumberOfTransitions() <= 1); |
||||
|
||||
if (state instanceof PlusBlockStartState) { |
||||
checkCondition(((PlusBlockStartState)state).loopBackState != null); |
||||
} |
||||
|
||||
if (state instanceof StarLoopEntryState) { |
||||
StarLoopEntryState starLoopEntryState = (StarLoopEntryState)state; |
||||
checkCondition(starLoopEntryState.loopBackState != null); |
||||
checkCondition(starLoopEntryState.getNumberOfTransitions() == 2); |
||||
|
||||
if (starLoopEntryState.transition(0).target instanceof StarBlockStartState) { |
||||
checkCondition(starLoopEntryState.transition(1).target instanceof LoopEndState); |
||||
checkCondition(!starLoopEntryState.nonGreedy); |
||||
} |
||||
else if (starLoopEntryState.transition(0).target instanceof LoopEndState) { |
||||
checkCondition(starLoopEntryState.transition(1).target instanceof StarBlockStartState); |
||||
checkCondition(starLoopEntryState.nonGreedy); |
||||
} |
||||
else { |
||||
throw new IllegalStateException(); |
||||
} |
||||
} |
||||
|
||||
if (state instanceof StarLoopbackState) { |
||||
checkCondition(state.getNumberOfTransitions() == 1); |
||||
checkCondition(state.transition(0).target instanceof StarLoopEntryState); |
||||
} |
||||
|
||||
if (state instanceof LoopEndState) { |
||||
checkCondition(((LoopEndState)state).loopBackState != null); |
||||
} |
||||
|
||||
if (state instanceof RuleStartState) { |
||||
checkCondition(((RuleStartState)state).stopState != null); |
||||
} |
||||
|
||||
if (state instanceof BlockStartState) { |
||||
checkCondition(((BlockStartState)state).endState != null); |
||||
} |
||||
|
||||
if (state instanceof BlockEndState) { |
||||
checkCondition(((BlockEndState)state).startState != null); |
||||
} |
||||
|
||||
if (state instanceof DecisionState) { |
||||
DecisionState decisionState = (DecisionState)state; |
||||
checkCondition(decisionState.getNumberOfTransitions() <= 1 || decisionState.decision >= 0); |
||||
} |
||||
else { |
||||
checkCondition(state.getNumberOfTransitions() <= 1 || state instanceof RuleStopState); |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected void checkCondition(boolean condition) { |
||||
checkCondition(condition, null); |
||||
} |
||||
|
||||
protected void checkCondition(boolean condition, String message) { |
||||
if (!condition) { |
||||
throw new IllegalStateException(message); |
||||
} |
||||
} |
||||
|
||||
protected static int toInt(char c) { |
||||
return c; |
||||
} |
||||
|
||||
protected static int toInt32(char[] data, int offset) { |
||||
return (int)data[offset] | ((int)data[offset + 1] << 16); |
||||
} |
||||
|
||||
protected static long toLong(char[] data, int offset) { |
||||
long lowOrder = toInt32(data, offset) & 0x00000000FFFFFFFFL; |
||||
return lowOrder | ((long)toInt32(data, offset + 2) << 32); |
||||
} |
||||
|
||||
protected static UUID toUUID(char[] data, int offset) { |
||||
long leastSigBits = toLong(data, offset); |
||||
long mostSigBits = toLong(data, offset + 4); |
||||
return new UUID(mostSigBits, leastSigBits); |
||||
} |
||||
|
||||
|
||||
protected Transition edgeFactory(ATN atn, |
||||
int type, int src, int trg, |
||||
int arg1, int arg2, int arg3, |
||||
List<IntervalSet> sets) |
||||
{ |
||||
ATNState target = atn.states.get(trg); |
||||
switch (type) { |
||||
case Transition.EPSILON : return new EpsilonTransition(target); |
||||
case Transition.RANGE : |
||||
if (arg3 != 0) { |
||||
return new RangeTransition(target, Token.EOF, arg2); |
||||
} |
||||
else { |
||||
return new RangeTransition(target, arg1, arg2); |
||||
} |
||||
case Transition.RULE : |
||||
RuleTransition rt = new RuleTransition((RuleStartState)atn.states.get(arg1), arg2, arg3, target); |
||||
return rt; |
||||
case Transition.PREDICATE : |
||||
PredicateTransition pt = new PredicateTransition(target, arg1, arg2, arg3 != 0); |
||||
return pt; |
||||
case Transition.PRECEDENCE: |
||||
return new PrecedencePredicateTransition(target, arg1); |
||||
case Transition.ATOM : |
||||
if (arg3 != 0) { |
||||
return new AtomTransition(target, Token.EOF); |
||||
} |
||||
else { |
||||
return new AtomTransition(target, arg1); |
||||
} |
||||
case Transition.ACTION : |
||||
ActionTransition a = new ActionTransition(target, arg1, arg2, arg3 != 0); |
||||
return a; |
||||
case Transition.SET : return new SetTransition(target, sets.get(arg1)); |
||||
case Transition.NOT_SET : return new NotSetTransition(target, sets.get(arg1)); |
||||
case Transition.WILDCARD : return new WildcardTransition(target); |
||||
} |
||||
|
||||
throw new IllegalArgumentException("The specified transition type is not valid."); |
||||
} |
||||
|
||||
protected ATNState stateFactory(int type, int ruleIndex) { |
||||
ATNState s; |
||||
switch (type) { |
||||
case ATNState.INVALID_TYPE: return null; |
||||
case ATNState.BASIC : s = new BasicState(); break; |
||||
case ATNState.RULE_START : s = new RuleStartState(); break; |
||||
case ATNState.BLOCK_START : s = new BasicBlockStartState(); break; |
||||
case ATNState.PLUS_BLOCK_START : s = new PlusBlockStartState(); break; |
||||
case ATNState.STAR_BLOCK_START : s = new StarBlockStartState(); break; |
||||
case ATNState.TOKEN_START : s = new TokensStartState(); break; |
||||
case ATNState.RULE_STOP : s = new RuleStopState(); break; |
||||
case ATNState.BLOCK_END : s = new BlockEndState(); break; |
||||
case ATNState.STAR_LOOP_BACK : s = new StarLoopbackState(); break; |
||||
case ATNState.STAR_LOOP_ENTRY : s = new StarLoopEntryState(); break; |
||||
case ATNState.PLUS_LOOP_BACK : s = new PlusLoopbackState(); break; |
||||
case ATNState.LOOP_END : s = new LoopEndState(); break; |
||||
default : |
||||
String message = String.format(Locale.getDefault(), "The specified state type %d is not valid.", type); |
||||
throw new IllegalArgumentException(message); |
||||
} |
||||
|
||||
s.ruleIndex = ruleIndex; |
||||
return s; |
||||
} |
||||
|
||||
protected LexerAction lexerActionFactory(LexerActionType type, int data1, int data2) { |
||||
switch (type) { |
||||
case CHANNEL: |
||||
return new LexerChannelAction(data1); |
||||
|
||||
case CUSTOM: |
||||
return new LexerCustomAction(data1, data2); |
||||
|
||||
case MODE: |
||||
return new LexerModeAction(data1); |
||||
|
||||
case MORE: |
||||
return LexerMoreAction.INSTANCE; |
||||
|
||||
case POP_MODE: |
||||
return LexerPopModeAction.INSTANCE; |
||||
|
||||
case PUSH_MODE: |
||||
return new LexerPushModeAction(data1); |
||||
|
||||
case SKIP: |
||||
return LexerSkipAction.INSTANCE; |
||||
|
||||
case TYPE: |
||||
return new LexerTypeAction(data1); |
||||
|
||||
default: |
||||
String message = String.format(Locale.getDefault(), "The specified lexer action type %d is not valid.", type); |
||||
throw new IllegalArgumentException(message); |
||||
} |
||||
} |
||||
} |
@ -1,628 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.Token; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntegerList; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntervalSet; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.Utils; |
||||
|
||||
import java.io.InvalidClassException; |
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.HashMap; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.List; |
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
import java.util.UUID; |
||||
|
||||
public class ATNSerializer { |
||||
public ATN atn; |
||||
private List<String> tokenNames; |
||||
|
||||
private interface CodePointSerializer { |
||||
void serializeCodePoint(IntegerList data, int cp); |
||||
} |
||||
|
||||
public ATNSerializer(ATN atn) { |
||||
assert atn.grammarType != null; |
||||
this.atn = atn; |
||||
} |
||||
|
||||
public ATNSerializer(ATN atn, List<String> tokenNames) { |
||||
assert atn.grammarType != null; |
||||
this.atn = atn; |
||||
this.tokenNames = tokenNames; |
||||
} |
||||
|
||||
/** Serialize state descriptors, edge descriptors, and decision→state map |
||||
* into list of ints: |
||||
* |
||||
* grammar-type, (ANTLRParser.LEXER, ...) |
||||
* max token type, |
||||
* num states, |
||||
* state-0-type ruleIndex, state-1-type ruleIndex, ... state-i-type ruleIndex optional-arg ... |
||||
* num rules, |
||||
* rule-1-start-state rule-1-args, rule-2-start-state rule-2-args, ... |
||||
* (args are token type,actionIndex in lexer else 0,0) |
||||
* num modes, |
||||
* mode-0-start-state, mode-1-start-state, ... (parser has 0 modes) |
||||
* num unicode-bmp-sets |
||||
* bmp-set-0-interval-count intervals, bmp-set-1-interval-count intervals, ... |
||||
* num unicode-smp-sets |
||||
* smp-set-0-interval-count intervals, smp-set-1-interval-count intervals, ... |
||||
* num total edges, |
||||
* src, trg, edge-type, edge arg1, optional edge arg2 (present always), ... |
||||
* num decisions, |
||||
* decision-0-start-state, decision-1-start-state, ... |
||||
* |
||||
* Convenient to pack into unsigned shorts to make as Java string. |
||||
*/ |
||||
public IntegerList serialize() { |
||||
IntegerList data = new IntegerList(); |
||||
data.add(ATNDeserializer.SERIALIZED_VERSION); |
||||
serializeUUID(data, ATNDeserializer.SERIALIZED_UUID); |
||||
|
||||
// convert grammar type to ATN const to avoid dependence on ANTLRParser
|
||||
data.add(atn.grammarType.ordinal()); |
||||
data.add(atn.maxTokenType); |
||||
int nedges = 0; |
||||
|
||||
// Note that we use a LinkedHashMap as a set to
|
||||
// maintain insertion order while deduplicating
|
||||
// entries with the same key.
|
||||
Map<IntervalSet, Boolean> sets = new LinkedHashMap<>(); |
||||
|
||||
// dump states, count edges and collect sets while doing so
|
||||
IntegerList nonGreedyStates = new IntegerList(); |
||||
IntegerList precedenceStates = new IntegerList(); |
||||
data.add(atn.states.size()); |
||||
for (ATNState s : atn.states) { |
||||
if ( s==null ) { // might be optimized away
|
||||
data.add(ATNState.INVALID_TYPE); |
||||
continue; |
||||
} |
||||
|
||||
int stateType = s.getStateType(); |
||||
if (s instanceof DecisionState && ((DecisionState)s).nonGreedy) { |
||||
nonGreedyStates.add(s.stateNumber); |
||||
} |
||||
|
||||
if (s instanceof RuleStartState && ((RuleStartState)s).isLeftRecursiveRule) { |
||||
precedenceStates.add(s.stateNumber); |
||||
} |
||||
|
||||
data.add(stateType); |
||||
|
||||
if (s.ruleIndex == -1) { |
||||
data.add(Character.MAX_VALUE); |
||||
} |
||||
else { |
||||
data.add(s.ruleIndex); |
||||
} |
||||
|
||||
if ( s.getStateType() == ATNState.LOOP_END ) { |
||||
data.add(((LoopEndState)s).loopBackState.stateNumber); |
||||
} |
||||
else if ( s instanceof BlockStartState ) { |
||||
data.add(((BlockStartState)s).endState.stateNumber); |
||||
} |
||||
|
||||
if (s.getStateType() != ATNState.RULE_STOP) { |
||||
// the deserializer can trivially derive these edges, so there's no need to serialize them
|
||||
nedges += s.getNumberOfTransitions(); |
||||
} |
||||
|
||||
for (int i=0; i<s.getNumberOfTransitions(); i++) { |
||||
Transition t = s.transition(i); |
||||
int edgeType = Transition.serializationTypes.get(t.getClass()); |
||||
if ( edgeType == Transition.SET || edgeType == Transition.NOT_SET ) { |
||||
SetTransition st = (SetTransition)t; |
||||
sets.put(st.set, true); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// non-greedy states
|
||||
data.add(nonGreedyStates.size()); |
||||
for (int i = 0; i < nonGreedyStates.size(); i++) { |
||||
data.add(nonGreedyStates.get(i)); |
||||
} |
||||
|
||||
// precedence states
|
||||
data.add(precedenceStates.size()); |
||||
for (int i = 0; i < precedenceStates.size(); i++) { |
||||
data.add(precedenceStates.get(i)); |
||||
} |
||||
|
||||
int nrules = atn.ruleToStartState.length; |
||||
data.add(nrules); |
||||
for (int r=0; r<nrules; r++) { |
||||
ATNState ruleStartState = atn.ruleToStartState[r]; |
||||
data.add(ruleStartState.stateNumber); |
||||
if (atn.grammarType == ATNType.LEXER) { |
||||
if (atn.ruleToTokenType[r] == Token.EOF) { |
||||
data.add(Character.MAX_VALUE); |
||||
} |
||||
else { |
||||
data.add(atn.ruleToTokenType[r]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
int nmodes = atn.modeToStartState.size(); |
||||
data.add(nmodes); |
||||
if ( nmodes>0 ) { |
||||
for (ATNState modeStartState : atn.modeToStartState) { |
||||
data.add(modeStartState.stateNumber); |
||||
} |
||||
} |
||||
List<IntervalSet> bmpSets = new ArrayList<>(); |
||||
List<IntervalSet> smpSets = new ArrayList<>(); |
||||
for (IntervalSet set : sets.keySet()) { |
||||
if (set.getMaxElement() <= Character.MAX_VALUE) { |
||||
bmpSets.add(set); |
||||
} |
||||
else { |
||||
smpSets.add(set); |
||||
} |
||||
} |
||||
serializeSets( |
||||
data, |
||||
bmpSets, |
||||
new CodePointSerializer() { |
||||
@Override |
||||
public void serializeCodePoint(IntegerList data, int cp) { |
||||
data.add(cp); |
||||
} |
||||
}); |
||||
serializeSets( |
||||
data, |
||||
smpSets, |
||||
new CodePointSerializer() { |
||||
@Override |
||||
public void serializeCodePoint(IntegerList data, int cp) { |
||||
serializeInt(data, cp); |
||||
} |
||||
}); |
||||
Map<IntervalSet, Integer> setIndices = new HashMap<>(); |
||||
int setIndex = 0; |
||||
for (IntervalSet bmpSet : bmpSets) { |
||||
setIndices.put(bmpSet, setIndex++); |
||||
} |
||||
for (IntervalSet smpSet : smpSets) { |
||||
setIndices.put(smpSet, setIndex++); |
||||
} |
||||
|
||||
data.add(nedges); |
||||
for (ATNState s : atn.states) { |
||||
if ( s==null ) { |
||||
// might be optimized away
|
||||
continue; |
||||
} |
||||
|
||||
if (s.getStateType() == ATNState.RULE_STOP) { |
||||
continue; |
||||
} |
||||
|
||||
for (int i=0; i<s.getNumberOfTransitions(); i++) { |
||||
Transition t = s.transition(i); |
||||
|
||||
if (atn.states.get(t.target.stateNumber) == null) { |
||||
throw new IllegalStateException("Cannot serialize a transition to a removed state."); |
||||
} |
||||
|
||||
int src = s.stateNumber; |
||||
int trg = t.target.stateNumber; |
||||
int edgeType = Transition.serializationTypes.get(t.getClass()); |
||||
int arg1 = 0; |
||||
int arg2 = 0; |
||||
int arg3 = 0; |
||||
switch ( edgeType ) { |
||||
case Transition.RULE : |
||||
trg = ((RuleTransition)t).followState.stateNumber; |
||||
arg1 = ((RuleTransition)t).target.stateNumber; |
||||
arg2 = ((RuleTransition)t).ruleIndex; |
||||
arg3 = ((RuleTransition)t).precedence; |
||||
break; |
||||
case Transition.PRECEDENCE: |
||||
PrecedencePredicateTransition ppt = (PrecedencePredicateTransition)t; |
||||
arg1 = ppt.precedence; |
||||
break; |
||||
case Transition.PREDICATE : |
||||
PredicateTransition pt = (PredicateTransition)t; |
||||
arg1 = pt.ruleIndex; |
||||
arg2 = pt.predIndex; |
||||
arg3 = pt.isCtxDependent ? 1 : 0 ; |
||||
break; |
||||
case Transition.RANGE : |
||||
arg1 = ((RangeTransition)t).from; |
||||
arg2 = ((RangeTransition)t).to; |
||||
if (arg1 == Token.EOF) { |
||||
arg1 = 0; |
||||
arg3 = 1; |
||||
} |
||||
|
||||
break; |
||||
case Transition.ATOM : |
||||
arg1 = ((AtomTransition)t).label; |
||||
if (arg1 == Token.EOF) { |
||||
arg1 = 0; |
||||
arg3 = 1; |
||||
} |
||||
|
||||
break; |
||||
case Transition.ACTION : |
||||
ActionTransition at = (ActionTransition)t; |
||||
arg1 = at.ruleIndex; |
||||
arg2 = at.actionIndex; |
||||
if (arg2 == -1) { |
||||
arg2 = 0xFFFF; |
||||
} |
||||
|
||||
arg3 = at.isCtxDependent ? 1 : 0 ; |
||||
break; |
||||
case Transition.SET : |
||||
arg1 = setIndices.get(((SetTransition)t).set); |
||||
break; |
||||
case Transition.NOT_SET : |
||||
arg1 = setIndices.get(((SetTransition)t).set); |
||||
break; |
||||
case Transition.WILDCARD : |
||||
break; |
||||
} |
||||
|
||||
data.add(src); |
||||
data.add(trg); |
||||
data.add(edgeType); |
||||
data.add(arg1); |
||||
data.add(arg2); |
||||
data.add(arg3); |
||||
} |
||||
} |
||||
|
||||
int ndecisions = atn.decisionToState.size(); |
||||
data.add(ndecisions); |
||||
for (DecisionState decStartState : atn.decisionToState) { |
||||
data.add(decStartState.stateNumber); |
||||
} |
||||
|
||||
//
|
||||
// LEXER ACTIONS
|
||||
//
|
||||
if (atn.grammarType == ATNType.LEXER) { |
||||
data.add(atn.lexerActions.length); |
||||
for (LexerAction action : atn.lexerActions) { |
||||
data.add(action.getActionType().ordinal()); |
||||
switch (action.getActionType()) { |
||||
case CHANNEL: |
||||
int channel = ((LexerChannelAction)action).getChannel(); |
||||
data.add(channel != -1 ? channel : 0xFFFF); |
||||
data.add(0); |
||||
break; |
||||
|
||||
case CUSTOM: |
||||
int ruleIndex = ((LexerCustomAction)action).getRuleIndex(); |
||||
int actionIndex = ((LexerCustomAction)action).getActionIndex(); |
||||
data.add(ruleIndex != -1 ? ruleIndex : 0xFFFF); |
||||
data.add(actionIndex != -1 ? actionIndex : 0xFFFF); |
||||
break; |
||||
|
||||
case MODE: |
||||
int mode = ((LexerModeAction)action).getMode(); |
||||
data.add(mode != -1 ? mode : 0xFFFF); |
||||
data.add(0); |
||||
break; |
||||
|
||||
case MORE: |
||||
data.add(0); |
||||
data.add(0); |
||||
break; |
||||
|
||||
case POP_MODE: |
||||
data.add(0); |
||||
data.add(0); |
||||
break; |
||||
|
||||
case PUSH_MODE: |
||||
mode = ((LexerPushModeAction)action).getMode(); |
||||
data.add(mode != -1 ? mode : 0xFFFF); |
||||
data.add(0); |
||||
break; |
||||
|
||||
case SKIP: |
||||
data.add(0); |
||||
data.add(0); |
||||
break; |
||||
|
||||
case TYPE: |
||||
int type = ((LexerTypeAction)action).getType(); |
||||
data.add(type != -1 ? type : 0xFFFF); |
||||
data.add(0); |
||||
break; |
||||
|
||||
default: |
||||
String message = String.format(Locale.getDefault(), "The specified lexer action type %s is not valid.", action.getActionType()); |
||||
throw new IllegalArgumentException(message); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Note: This value shifting loop is documented in ATNDeserializer.
|
||||
// don't adjust the first value since that's the version number
|
||||
for (int i = 1; i < data.size(); i++) { |
||||
if (data.get(i) < Character.MIN_VALUE || data.get(i) > Character.MAX_VALUE) { |
||||
throw new UnsupportedOperationException("Serialized ATN data element "+ |
||||
data.get(i)+ |
||||
" element "+i+" out of range "+ |
||||
(int)Character.MIN_VALUE+ |
||||
".."+ |
||||
(int)Character.MAX_VALUE); |
||||
} |
||||
|
||||
int value = (data.get(i) + 2) & 0xFFFF; |
||||
data.set(i, value); |
||||
} |
||||
|
||||
return data; |
||||
} |
||||
|
||||
private static void serializeSets( |
||||
IntegerList data, |
||||
Collection<IntervalSet> sets, |
||||
CodePointSerializer codePointSerializer) |
||||
{ |
||||
int nSets = sets.size(); |
||||
data.add(nSets); |
||||
|
||||
for (IntervalSet set : sets) { |
||||
boolean containsEof = set.contains(Token.EOF); |
||||
if (containsEof && set.getIntervals().get(0).b == Token.EOF) { |
||||
data.add(set.getIntervals().size() - 1); |
||||
} |
||||
else { |
||||
data.add(set.getIntervals().size()); |
||||
} |
||||
|
||||
data.add(containsEof ? 1 : 0); |
||||
for (Interval I : set.getIntervals()) { |
||||
if (I.a == Token.EOF) { |
||||
if (I.b == Token.EOF) { |
||||
continue; |
||||
} |
||||
else { |
||||
codePointSerializer.serializeCodePoint(data, 0); |
||||
} |
||||
} |
||||
else { |
||||
codePointSerializer.serializeCodePoint(data, I.a); |
||||
} |
||||
|
||||
codePointSerializer.serializeCodePoint(data, I.b); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public String decode(char[] data) { |
||||
data = data.clone(); |
||||
// don't adjust the first value since that's the version number
|
||||
for (int i = 1; i < data.length; i++) { |
||||
data[i] = (char)(data[i] - 2); |
||||
} |
||||
|
||||
StringBuilder buf = new StringBuilder(); |
||||
int p = 0; |
||||
int version = ATNDeserializer.toInt(data[p++]); |
||||
if (version != ATNDeserializer.SERIALIZED_VERSION) { |
||||
String reason = String.format("Could not deserialize ATN with version %d (expected %d).", version, ATNDeserializer.SERIALIZED_VERSION); |
||||
throw new UnsupportedOperationException(new InvalidClassException(ATN.class.getName(), reason)); |
||||
} |
||||
|
||||
UUID uuid = ATNDeserializer.toUUID(data, p); |
||||
p += 8; |
||||
if (!uuid.equals(ATNDeserializer.SERIALIZED_UUID)) { |
||||
String reason = String.format(Locale.getDefault(), "Could not deserialize ATN with UUID %s (expected %s).", uuid, ATNDeserializer.SERIALIZED_UUID); |
||||
throw new UnsupportedOperationException(new InvalidClassException(ATN.class.getName(), reason)); |
||||
} |
||||
|
||||
p++; // skip grammarType
|
||||
int maxType = ATNDeserializer.toInt(data[p++]); |
||||
buf.append("max type ").append(maxType).append("\n"); |
||||
int nstates = ATNDeserializer.toInt(data[p++]); |
||||
for (int i=0; i<nstates; i++) { |
||||
int stype = ATNDeserializer.toInt(data[p++]); |
||||
if ( stype==ATNState.INVALID_TYPE ) continue; // ignore bad type of states
|
||||
int ruleIndex = ATNDeserializer.toInt(data[p++]); |
||||
if (ruleIndex == Character.MAX_VALUE) { |
||||
ruleIndex = -1; |
||||
} |
||||
|
||||
String arg = ""; |
||||
if ( stype == ATNState.LOOP_END ) { |
||||
int loopBackStateNumber = ATNDeserializer.toInt(data[p++]); |
||||
arg = " "+loopBackStateNumber; |
||||
} |
||||
else if ( stype == ATNState.PLUS_BLOCK_START || stype == ATNState.STAR_BLOCK_START || stype == ATNState.BLOCK_START ) { |
||||
int endStateNumber = ATNDeserializer.toInt(data[p++]); |
||||
arg = " "+endStateNumber; |
||||
} |
||||
buf.append(i).append(":") |
||||
.append(ATNState.serializationNames.get(stype)).append(" ") |
||||
.append(ruleIndex).append(arg).append("\n"); |
||||
} |
||||
// this code is meant to model the form of ATNDeserializer.deserialize,
|
||||
// since both need to be updated together whenever a change is made to
|
||||
// the serialization format. The "dead" code is only used in debugging
|
||||
// and testing scenarios, so the form you see here was kept for
|
||||
// improved maintainability.
|
||||
// start
|
||||
int numNonGreedyStates = ATNDeserializer.toInt(data[p++]); |
||||
for (int i = 0; i < numNonGreedyStates; i++) { |
||||
int stateNumber = ATNDeserializer.toInt(data[p++]); |
||||
} |
||||
int numPrecedenceStates = ATNDeserializer.toInt(data[p++]); |
||||
for (int i = 0; i < numPrecedenceStates; i++) { |
||||
int stateNumber = ATNDeserializer.toInt(data[p++]); |
||||
} |
||||
// finish
|
||||
int nrules = ATNDeserializer.toInt(data[p++]); |
||||
for (int i=0; i<nrules; i++) { |
||||
int s = ATNDeserializer.toInt(data[p++]); |
||||
if (atn.grammarType == ATNType.LEXER) { |
||||
int arg1 = ATNDeserializer.toInt(data[p++]); |
||||
buf.append("rule ").append(i).append(":").append(s).append(" ").append(arg1).append('\n'); |
||||
} |
||||
else { |
||||
buf.append("rule ").append(i).append(":").append(s).append('\n'); |
||||
} |
||||
} |
||||
int nmodes = ATNDeserializer.toInt(data[p++]); |
||||
for (int i=0; i<nmodes; i++) { |
||||
int s = ATNDeserializer.toInt(data[p++]); |
||||
buf.append("mode ").append(i).append(":").append(s).append('\n'); |
||||
} |
||||
int numBMPSets = ATNDeserializer.toInt(data[p++]); |
||||
p = appendSets(buf, data, p, numBMPSets, 0, ATNDeserializer.getUnicodeDeserializer(ATNDeserializer.UnicodeDeserializingMode.UNICODE_BMP)); |
||||
int numSMPSets = ATNDeserializer.toInt(data[p++]); |
||||
p = appendSets(buf, data, p, numSMPSets, numBMPSets, ATNDeserializer.getUnicodeDeserializer(ATNDeserializer.UnicodeDeserializingMode.UNICODE_SMP)); |
||||
int nedges = ATNDeserializer.toInt(data[p++]); |
||||
for (int i=0; i<nedges; i++) { |
||||
int src = ATNDeserializer.toInt(data[p]); |
||||
int trg = ATNDeserializer.toInt(data[p + 1]); |
||||
int ttype = ATNDeserializer.toInt(data[p + 2]); |
||||
int arg1 = ATNDeserializer.toInt(data[p + 3]); |
||||
int arg2 = ATNDeserializer.toInt(data[p + 4]); |
||||
int arg3 = ATNDeserializer.toInt(data[p + 5]); |
||||
buf.append(src).append("->").append(trg) |
||||
.append(" ").append(Transition.serializationNames.get(ttype)) |
||||
.append(" ").append(arg1).append(",").append(arg2).append(",").append(arg3) |
||||
.append("\n"); |
||||
p += 6; |
||||
} |
||||
int ndecisions = ATNDeserializer.toInt(data[p++]); |
||||
for (int i=0; i<ndecisions; i++) { |
||||
int s = ATNDeserializer.toInt(data[p++]); |
||||
buf.append(i).append(":").append(s).append("\n"); |
||||
} |
||||
if (atn.grammarType == ATNType.LEXER) { |
||||
// this code is meant to model the form of ATNDeserializer.deserialize,
|
||||
// since both need to be updated together whenever a change is made to
|
||||
// the serialization format. The "dead" code is only used in debugging
|
||||
// and testing scenarios, so the form you see here was kept for
|
||||
// improved maintainability.
|
||||
int lexerActionCount = ATNDeserializer.toInt(data[p++]); |
||||
for (int i = 0; i < lexerActionCount; i++) { |
||||
LexerActionType actionType = LexerActionType.values()[ATNDeserializer.toInt(data[p++])]; |
||||
int data1 = ATNDeserializer.toInt(data[p++]); |
||||
int data2 = ATNDeserializer.toInt(data[p++]); |
||||
} |
||||
} |
||||
return buf.toString(); |
||||
} |
||||
|
||||
private int appendSets(StringBuilder buf, char[] data, int p, int nsets, int setIndexOffset, ATNDeserializer.UnicodeDeserializer unicodeDeserializer) { |
||||
for (int i=0; i<nsets; i++) { |
||||
int nintervals = ATNDeserializer.toInt(data[p++]); |
||||
buf.append(i+setIndexOffset).append(":"); |
||||
boolean containsEof = data[p++] != 0; |
||||
if (containsEof) { |
||||
buf.append(getTokenName(Token.EOF)); |
||||
} |
||||
|
||||
for (int j=0; j<nintervals; j++) { |
||||
if ( containsEof || j>0 ) { |
||||
buf.append(", "); |
||||
} |
||||
|
||||
int a = unicodeDeserializer.readUnicode(data, p); |
||||
p += unicodeDeserializer.size(); |
||||
int b = unicodeDeserializer.readUnicode(data, p); |
||||
p += unicodeDeserializer.size(); |
||||
buf.append(getTokenName(a)).append("..").append(getTokenName(b)); |
||||
} |
||||
buf.append("\n"); |
||||
} |
||||
return p; |
||||
} |
||||
|
||||
public String getTokenName(int t) { |
||||
if ( t==-1 ) return "EOF"; |
||||
|
||||
if ( atn.grammarType == ATNType.LEXER && |
||||
t >= Character.MIN_VALUE && t <= Character.MAX_VALUE ) |
||||
{ |
||||
switch (t) { |
||||
case '\n': |
||||
return "'\\n'"; |
||||
case '\r': |
||||
return "'\\r'"; |
||||
case '\t': |
||||
return "'\\t'"; |
||||
case '\b': |
||||
return "'\\b'"; |
||||
case '\f': |
||||
return "'\\f'"; |
||||
case '\\': |
||||
return "'\\\\'"; |
||||
case '\'': |
||||
return "'\\''"; |
||||
default: |
||||
if ( Character.UnicodeBlock.of((char)t)==Character.UnicodeBlock.BASIC_LATIN && |
||||
!Character.isISOControl((char)t) ) { |
||||
return '\''+Character.toString((char)t)+'\''; |
||||
} |
||||
// turn on the bit above max "\uFFFF" value so that we pad with zeros
|
||||
// then only take last 4 digits
|
||||
String hex = Integer.toHexString(t|0x10000).toUpperCase().substring(1,5); |
||||
String unicodeStr = "'\\u"+hex+"'"; |
||||
return unicodeStr; |
||||
} |
||||
} |
||||
|
||||
if (tokenNames != null && t >= 0 && t < tokenNames.size()) { |
||||
return tokenNames.get(t); |
||||
} |
||||
|
||||
return String.valueOf(t); |
||||
} |
||||
|
||||
/** Used by Java target to encode short/int array as chars in string. */ |
||||
public static String getSerializedAsString(ATN atn) { |
||||
return new String(getSerializedAsChars(atn)); |
||||
} |
||||
|
||||
public static IntegerList getSerialized(ATN atn) { |
||||
return new ATNSerializer(atn).serialize(); |
||||
} |
||||
|
||||
public static char[] getSerializedAsChars(ATN atn) { |
||||
return Utils.toCharArray(getSerialized(atn)); |
||||
} |
||||
|
||||
public static String getDecoded(ATN atn, List<String> tokenNames) { |
||||
IntegerList serialized = getSerialized(atn); |
||||
char[] data = Utils.toCharArray(serialized); |
||||
return new ATNSerializer(atn, tokenNames).decode(data); |
||||
} |
||||
|
||||
private void serializeUUID(IntegerList data, UUID uuid) { |
||||
serializeLong(data, uuid.getLeastSignificantBits()); |
||||
serializeLong(data, uuid.getMostSignificantBits()); |
||||
} |
||||
|
||||
private void serializeLong(IntegerList data, long value) { |
||||
serializeInt(data, (int)value); |
||||
serializeInt(data, (int)(value >> 32)); |
||||
} |
||||
|
||||
private void serializeInt(IntegerList data, int value) { |
||||
data.add((char)value); |
||||
data.add((char)(value >> 16)); |
||||
} |
||||
} |
@ -1,186 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.dfa.DFAState; |
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntervalSet; |
||||
|
||||
import java.util.IdentityHashMap; |
||||
import java.util.List; |
||||
import java.util.UUID; |
||||
|
||||
public abstract class ATNSimulator { |
||||
/** |
||||
* @deprecated Use {@link ATNDeserializer#SERIALIZED_VERSION} instead. |
||||
*/ |
||||
@Deprecated |
||||
public static final int SERIALIZED_VERSION; |
||||
static { |
||||
SERIALIZED_VERSION = ATNDeserializer.SERIALIZED_VERSION; |
||||
} |
||||
|
||||
/** |
||||
* This is the current serialized UUID. |
||||
* @deprecated Use {@link ATNDeserializer#checkCondition(boolean)} instead. |
||||
*/ |
||||
@Deprecated |
||||
public static final UUID SERIALIZED_UUID; |
||||
static { |
||||
SERIALIZED_UUID = ATNDeserializer.SERIALIZED_UUID; |
||||
} |
||||
|
||||
/** Must distinguish between missing edge and edge we know leads nowhere */ |
||||
|
||||
public static final DFAState ERROR; |
||||
|
||||
public final ATN atn; |
||||
|
||||
/** The context cache maps all PredictionContext objects that are equals() |
||||
* to a single cached copy. This cache is shared across all contexts |
||||
* in all ATNConfigs in all DFA states. We rebuild each ATNConfigSet |
||||
* to use only cached nodes/graphs in addDFAState(). We don't want to |
||||
* fill this during closure() since there are lots of contexts that |
||||
* pop up but are not used ever again. It also greatly slows down closure(). |
||||
* |
||||
* <p>This cache makes a huge difference in memory and a little bit in speed. |
||||
* For the Java grammar on java.*, it dropped the memory requirements |
||||
* at the end from 25M to 16M. We don't store any of the full context |
||||
* graphs in the DFA because they are limited to local context only, |
||||
* but apparently there's a lot of repetition there as well. We optimize |
||||
* the config contexts before storing the config set in the DFA states |
||||
* by literally rebuilding them with cached subgraphs only.</p> |
||||
* |
||||
* <p>I tried a cache for use during closure operations, that was |
||||
* whacked after each adaptivePredict(). It cost a little bit |
||||
* more time I think and doesn't save on the overall footprint |
||||
* so it's not worth the complexity.</p> |
||||
*/ |
||||
protected final PredictionContextCache sharedContextCache; |
||||
|
||||
static { |
||||
ERROR = new DFAState(new ATNConfigSet()); |
||||
ERROR.stateNumber = Integer.MAX_VALUE; |
||||
} |
||||
|
||||
public ATNSimulator(ATN atn, |
||||
PredictionContextCache sharedContextCache) |
||||
{ |
||||
this.atn = atn; |
||||
this.sharedContextCache = sharedContextCache; |
||||
} |
||||
|
||||
public abstract void reset(); |
||||
|
||||
/** |
||||
* Clear the DFA cache used by the current instance. Since the DFA cache may |
||||
* be shared by multiple ATN simulators, this method may affect the |
||||
* performance (but not accuracy) of other parsers which are being used |
||||
* concurrently. |
||||
* |
||||
* @throws UnsupportedOperationException if the current instance does not |
||||
* support clearing the DFA. |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public void clearDFA() { |
||||
throw new UnsupportedOperationException("This ATN simulator does not support clearing the DFA."); |
||||
} |
||||
|
||||
public PredictionContextCache getSharedContextCache() { |
||||
return sharedContextCache; |
||||
} |
||||
|
||||
public PredictionContext getCachedContext(PredictionContext context) { |
||||
if ( sharedContextCache==null ) return context; |
||||
|
||||
synchronized (sharedContextCache) { |
||||
IdentityHashMap<PredictionContext, PredictionContext> visited = |
||||
new IdentityHashMap<PredictionContext, PredictionContext>(); |
||||
return PredictionContext.getCachedContext(context, |
||||
sharedContextCache, |
||||
visited); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @deprecated Use {@link ATNDeserializer#deserialize} instead. |
||||
*/ |
||||
@Deprecated |
||||
public static ATN deserialize(char[] data) { |
||||
return new ATNDeserializer().deserialize(data); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated Use {@link ATNDeserializer#checkCondition(boolean)} instead. |
||||
*/ |
||||
@Deprecated |
||||
public static void checkCondition(boolean condition) { |
||||
new ATNDeserializer().checkCondition(condition); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated Use {@link ATNDeserializer#checkCondition(boolean, String)} instead. |
||||
*/ |
||||
@Deprecated |
||||
public static void checkCondition(boolean condition, String message) { |
||||
new ATNDeserializer().checkCondition(condition, message); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated Use {@link ATNDeserializer#toInt} instead. |
||||
*/ |
||||
@Deprecated |
||||
public static int toInt(char c) { |
||||
return ATNDeserializer.toInt(c); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated Use {@link ATNDeserializer#toInt32} instead. |
||||
*/ |
||||
@Deprecated |
||||
public static int toInt32(char[] data, int offset) { |
||||
return ATNDeserializer.toInt32(data, offset); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated Use {@link ATNDeserializer#toLong} instead. |
||||
*/ |
||||
@Deprecated |
||||
public static long toLong(char[] data, int offset) { |
||||
return ATNDeserializer.toLong(data, offset); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated Use {@link ATNDeserializer#toUUID} instead. |
||||
*/ |
||||
@Deprecated |
||||
public static UUID toUUID(char[] data, int offset) { |
||||
return ATNDeserializer.toUUID(data, offset); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated Use {@link ATNDeserializer#edgeFactory} instead. |
||||
*/ |
||||
@Deprecated |
||||
|
||||
public static Transition edgeFactory(ATN atn, |
||||
int type, int src, int trg, |
||||
int arg1, int arg2, int arg3, |
||||
List<IntervalSet> sets) |
||||
{ |
||||
return new ATNDeserializer().edgeFactory(atn, type, src, trg, arg1, arg2, arg3, sets); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated Use {@link ATNDeserializer#stateFactory} instead. |
||||
*/ |
||||
@Deprecated |
||||
public static ATNState stateFactory(int type, int ruleIndex) { |
||||
return new ATNDeserializer().stateFactory(type, ruleIndex); |
||||
} |
||||
|
||||
} |
@ -1,207 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntervalSet; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Arrays; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
import java.util.Locale; |
||||
|
||||
/** |
||||
* The following images show the relation of states and |
||||
* {@link ATNState#transitions} for various grammar constructs. |
||||
* |
||||
* <ul> |
||||
* |
||||
* <li>Solid edges marked with an ε indicate a required |
||||
* {@link EpsilonTransition}.</li> |
||||
* |
||||
* <li>Dashed edges indicate locations where any transition derived from |
||||
* {@link Transition} might appear.</li> |
||||
* |
||||
* <li>Dashed nodes are place holders for either a sequence of linked |
||||
* {@link BasicState} states or the inclusion of a block representing a nested |
||||
* construct in one of the forms below.</li> |
||||
* |
||||
* <li>Nodes showing multiple outgoing alternatives with a {@code ...} support |
||||
* any number of alternatives (one or more). Nodes without the {@code ...} only |
||||
* support the exact number of alternatives shown in the diagram.</li> |
||||
* |
||||
* </ul> |
||||
* |
||||
* <h2>Basic Blocks</h2> |
||||
* |
||||
* <h3>Rule</h3> |
||||
* |
||||
* <embed src="images/Rule.svg" type="image/svg+xml"/> |
||||
* |
||||
* <h3>Block of 1 or more alternatives</h3> |
||||
* |
||||
* <embed src="images/Block.svg" type="image/svg+xml"/> |
||||
* |
||||
* <h2>Greedy Loops</h2> |
||||
* |
||||
* <h3>Greedy Closure: {@code (...)*}</h3> |
||||
* |
||||
* <embed src="images/ClosureGreedy.svg" type="image/svg+xml"/> |
||||
* |
||||
* <h3>Greedy Positive Closure: {@code (...)+}</h3> |
||||
* |
||||
* <embed src="images/PositiveClosureGreedy.svg" type="image/svg+xml"/> |
||||
* |
||||
* <h3>Greedy Optional: {@code (...)?}</h3> |
||||
* |
||||
* <embed src="images/OptionalGreedy.svg" type="image/svg+xml"/> |
||||
* |
||||
* <h2>Non-Greedy Loops</h2> |
||||
* |
||||
* <h3>Non-Greedy Closure: {@code (...)*?}</h3> |
||||
* |
||||
* <embed src="images/ClosureNonGreedy.svg" type="image/svg+xml"/> |
||||
* |
||||
* <h3>Non-Greedy Positive Closure: {@code (...)+?}</h3> |
||||
* |
||||
* <embed src="images/PositiveClosureNonGreedy.svg" type="image/svg+xml"/> |
||||
* |
||||
* <h3>Non-Greedy Optional: {@code (...)??}</h3> |
||||
* |
||||
* <embed src="images/OptionalNonGreedy.svg" type="image/svg+xml"/> |
||||
*/ |
||||
public abstract class ATNState { |
||||
public static final int INITIAL_NUM_TRANSITIONS = 4; |
||||
|
||||
// constants for serialization
|
||||
public static final int INVALID_TYPE = 0; |
||||
public static final int BASIC = 1; |
||||
public static final int RULE_START = 2; |
||||
public static final int BLOCK_START = 3; |
||||
public static final int PLUS_BLOCK_START = 4; |
||||
public static final int STAR_BLOCK_START = 5; |
||||
public static final int TOKEN_START = 6; |
||||
public static final int RULE_STOP = 7; |
||||
public static final int BLOCK_END = 8; |
||||
public static final int STAR_LOOP_BACK = 9; |
||||
public static final int STAR_LOOP_ENTRY = 10; |
||||
public static final int PLUS_LOOP_BACK = 11; |
||||
public static final int LOOP_END = 12; |
||||
|
||||
public static final List<String> serializationNames = |
||||
Collections.unmodifiableList(Arrays.asList( |
||||
"INVALID", |
||||
"BASIC", |
||||
"RULE_START", |
||||
"BLOCK_START", |
||||
"PLUS_BLOCK_START", |
||||
"STAR_BLOCK_START", |
||||
"TOKEN_START", |
||||
"RULE_STOP", |
||||
"BLOCK_END", |
||||
"STAR_LOOP_BACK", |
||||
"STAR_LOOP_ENTRY", |
||||
"PLUS_LOOP_BACK", |
||||
"LOOP_END" |
||||
)); |
||||
|
||||
public static final int INVALID_STATE_NUMBER = -1; |
||||
|
||||
/** Which ATN are we in? */ |
||||
public ATN atn = null; |
||||
|
||||
public int stateNumber = INVALID_STATE_NUMBER; |
||||
|
||||
public int ruleIndex; // at runtime, we don't have Rule objects
|
||||
|
||||
public boolean epsilonOnlyTransitions = false; |
||||
|
||||
/** Track the transitions emanating from this ATN state. */ |
||||
protected final List<Transition> transitions = |
||||
new ArrayList<Transition>(INITIAL_NUM_TRANSITIONS); |
||||
|
||||
/** Used to cache lookahead during parsing, not used during construction */ |
||||
public IntervalSet nextTokenWithinRule; |
||||
|
||||
@Override |
||||
public int hashCode() { return stateNumber; } |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
// are these states same object?
|
||||
if ( o instanceof ATNState ) return stateNumber==((ATNState)o).stateNumber; |
||||
return false; |
||||
} |
||||
|
||||
public boolean isNonGreedyExitState() { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return String.valueOf(stateNumber); |
||||
} |
||||
|
||||
public Transition[] getTransitions() { |
||||
return transitions.toArray(new Transition[transitions.size()]); |
||||
} |
||||
|
||||
public int getNumberOfTransitions() { |
||||
return transitions.size(); |
||||
} |
||||
|
||||
public void addTransition(Transition e) { |
||||
addTransition(transitions.size(), e); |
||||
} |
||||
|
||||
public void addTransition(int index, Transition e) { |
||||
if (transitions.isEmpty()) { |
||||
epsilonOnlyTransitions = e.isEpsilon(); |
||||
} |
||||
else if (epsilonOnlyTransitions != e.isEpsilon()) { |
||||
System.err.format(Locale.getDefault(), "ATN state %d has both epsilon and non-epsilon transitions.\n", stateNumber); |
||||
epsilonOnlyTransitions = false; |
||||
} |
||||
|
||||
boolean alreadyPresent = false; |
||||
for (Transition t : transitions) { |
||||
if ( t.target.stateNumber == e.target.stateNumber ) { |
||||
if ( t.label()!=null && e.label()!=null && t.label().equals(e.label()) ) { |
||||
// System.err.println("Repeated transition upon "+e.label()+" from "+stateNumber+"->"+t.target.stateNumber);
|
||||
alreadyPresent = true; |
||||
break; |
||||
} |
||||
else if ( t.isEpsilon() && e.isEpsilon() ) { |
||||
// System.err.println("Repeated epsilon transition from "+stateNumber+"->"+t.target.stateNumber);
|
||||
alreadyPresent = true; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if ( !alreadyPresent ) { |
||||
transitions.add(index, e); |
||||
} |
||||
} |
||||
|
||||
public Transition transition(int i) { return transitions.get(i); } |
||||
|
||||
public void setTransition(int i, Transition e) { |
||||
transitions.set(i, e); |
||||
} |
||||
|
||||
public Transition removeTransition(int index) { |
||||
return transitions.remove(index); |
||||
} |
||||
|
||||
public abstract int getStateType(); |
||||
|
||||
public final boolean onlyHasEpsilonTransitions() { |
||||
return epsilonOnlyTransitions; |
||||
} |
||||
|
||||
public void setRuleIndex(int ruleIndex) { this.ruleIndex = ruleIndex; } |
||||
} |
@ -1,26 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
/** |
||||
* Represents the type of recognizer an ATN applies to. |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public enum ATNType { |
||||
|
||||
/** |
||||
* A lexer grammar. |
||||
*/ |
||||
LEXER, |
||||
|
||||
/** |
||||
* A parser grammar. |
||||
*/ |
||||
PARSER, |
||||
|
||||
} |
@ -1,19 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
/** |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public abstract class AbstractPredicateTransition extends Transition { |
||||
|
||||
public AbstractPredicateTransition(com.fr.third.org.antlr.v4.runtime.atn.ATNState target) { |
||||
super(target); |
||||
} |
||||
|
||||
} |
@ -1,44 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
public final class ActionTransition extends Transition { |
||||
public final int ruleIndex; |
||||
public final int actionIndex; |
||||
public final boolean isCtxDependent; // e.g., $i ref in action
|
||||
|
||||
public ActionTransition(ATNState target, int ruleIndex) { |
||||
this(target, ruleIndex, -1, false); |
||||
} |
||||
|
||||
public ActionTransition(ATNState target, int ruleIndex, int actionIndex, boolean isCtxDependent) { |
||||
super(target); |
||||
this.ruleIndex = ruleIndex; |
||||
this.actionIndex = actionIndex; |
||||
this.isCtxDependent = isCtxDependent; |
||||
} |
||||
|
||||
@Override |
||||
public int getSerializationType() { |
||||
return ACTION; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEpsilon() { |
||||
return true; // we are to be ignored by analysis 'cept for predicates
|
||||
} |
||||
|
||||
@Override |
||||
public boolean matches(int symbol, int minVocabSymbol, int maxVocabSymbol) { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "action_"+ruleIndex+":"+actionIndex; |
||||
} |
||||
} |
@ -1,73 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.ANTLRErrorListener; |
||||
import com.fr.third.org.antlr.v4.runtime.TokenStream; |
||||
|
||||
import java.util.BitSet; |
||||
|
||||
/** |
||||
* This class represents profiling event information for an ambiguity. |
||||
* Ambiguities are decisions where a particular input resulted in an SLL |
||||
* conflict, followed by LL prediction also reaching a conflict state |
||||
* (indicating a true ambiguity in the grammar). |
||||
* |
||||
* <p> |
||||
* This event may be reported during SLL prediction in cases where the |
||||
* conflicting SLL configuration set provides sufficient information to |
||||
* determine that the SLL conflict is truly an ambiguity. For example, if none |
||||
* of the ATN configurations in the conflicting SLL configuration set have |
||||
* traversed a global follow transition (i.e. |
||||
* {@link ATNConfig#reachesIntoOuterContext} is 0 for all configurations), then |
||||
* the result of SLL prediction for that input is known to be equivalent to the |
||||
* result of LL prediction for that input.</p> |
||||
* |
||||
* <p> |
||||
* In some cases, the minimum represented alternative in the conflicting LL |
||||
* configuration set is not equal to the minimum represented alternative in the |
||||
* conflicting SLL configuration set. Grammars and inputs which result in this |
||||
* scenario are unable to use {@link PredictionMode#SLL}, which in turn means |
||||
* they cannot use the two-stage parsing strategy to improve parsing performance |
||||
* for that input.</p> |
||||
* |
||||
* @see ParserATNSimulator#reportAmbiguity |
||||
* @see ANTLRErrorListener#reportAmbiguity |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public class AmbiguityInfo extends DecisionEventInfo { |
||||
/** The set of alternative numbers for this decision event that lead to a valid parse. */ |
||||
public BitSet ambigAlts; |
||||
|
||||
/** |
||||
* Constructs a new instance of the {@link AmbiguityInfo} class with the |
||||
* specified detailed ambiguity information. |
||||
* |
||||
* @param decision The decision number |
||||
* @param configs The final configuration set identifying the ambiguous |
||||
* alternatives for the current input |
||||
* @param ambigAlts The set of alternatives in the decision that lead to a valid parse. |
||||
* The predicted alt is the min(ambigAlts) |
||||
* @param input The input token stream |
||||
* @param startIndex The start index for the current prediction |
||||
* @param stopIndex The index at which the ambiguity was identified during |
||||
* prediction |
||||
* @param fullCtx {@code true} if the ambiguity was identified during LL |
||||
* prediction; otherwise, {@code false} if the ambiguity was identified |
||||
* during SLL prediction |
||||
*/ |
||||
public AmbiguityInfo(int decision, |
||||
ATNConfigSet configs, |
||||
BitSet ambigAlts, |
||||
TokenStream input, int startIndex, int stopIndex, |
||||
boolean fullCtx) |
||||
{ |
||||
super(decision, configs, input, startIndex, stopIndex, fullCtx); |
||||
this.ambigAlts = ambigAlts; |
||||
} |
||||
} |
@ -1,104 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
public class ArrayPredictionContext extends PredictionContext { |
||||
/** Parent can be null only if full ctx mode and we make an array |
||||
* from {@link #EMPTY} and non-empty. We merge {@link #EMPTY} by using null parent and |
||||
* returnState == {@link #EMPTY_RETURN_STATE}. |
||||
*/ |
||||
public final PredictionContext[] parents; |
||||
|
||||
/** Sorted for merge, no duplicates; if present, |
||||
* {@link #EMPTY_RETURN_STATE} is always last. |
||||
*/ |
||||
public final int[] returnStates; |
||||
|
||||
public ArrayPredictionContext(SingletonPredictionContext a) { |
||||
this(new PredictionContext[] {a.parent}, new int[] {a.returnState}); |
||||
} |
||||
|
||||
public ArrayPredictionContext(PredictionContext[] parents, int[] returnStates) { |
||||
super(calculateHashCode(parents, returnStates)); |
||||
assert parents!=null && parents.length>0; |
||||
assert returnStates!=null && returnStates.length>0; |
||||
// System.err.println("CREATE ARRAY: "+Arrays.toString(parents)+", "+Arrays.toString(returnStates));
|
||||
this.parents = parents; |
||||
this.returnStates = returnStates; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
// since EMPTY_RETURN_STATE can only appear in the last position, we
|
||||
// don't need to verify that size==1
|
||||
return returnStates[0]==EMPTY_RETURN_STATE; |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return returnStates.length; |
||||
} |
||||
|
||||
@Override |
||||
public PredictionContext getParent(int index) { |
||||
return parents[index]; |
||||
} |
||||
|
||||
@Override |
||||
public int getReturnState(int index) { |
||||
return returnStates[index]; |
||||
} |
||||
|
||||
// @Override
|
||||
// public int findReturnState(int returnState) {
|
||||
// return Arrays.binarySearch(returnStates, returnState);
|
||||
// }
|
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) { |
||||
return true; |
||||
} |
||||
else if ( !(o instanceof ArrayPredictionContext) ) { |
||||
return false; |
||||
} |
||||
|
||||
if ( this.hashCode() != o.hashCode() ) { |
||||
return false; // can't be same if hash is different
|
||||
} |
||||
|
||||
ArrayPredictionContext a = (ArrayPredictionContext)o; |
||||
return Arrays.equals(returnStates, a.returnStates) && |
||||
Arrays.equals(parents, a.parents); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
if ( isEmpty() ) return "[]"; |
||||
StringBuilder buf = new StringBuilder(); |
||||
buf.append("["); |
||||
for (int i=0; i<returnStates.length; i++) { |
||||
if ( i>0 ) buf.append(", "); |
||||
if ( returnStates[i]==EMPTY_RETURN_STATE ) { |
||||
buf.append("$"); |
||||
continue; |
||||
} |
||||
buf.append(returnStates[i]); |
||||
if ( parents[i]!=null ) { |
||||
buf.append(' '); |
||||
buf.append(parents[i].toString()); |
||||
} |
||||
else { |
||||
buf.append("null"); |
||||
} |
||||
} |
||||
buf.append("]"); |
||||
return buf.toString(); |
||||
} |
||||
} |
@ -1,39 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntervalSet; |
||||
|
||||
/** TODO: make all transitions sets? no, should remove set edges */ |
||||
public final class AtomTransition extends Transition { |
||||
/** The token type or character value; or, signifies special label. */ |
||||
public final int label; |
||||
|
||||
public AtomTransition(ATNState target, int label) { |
||||
super(target); |
||||
this.label = label; |
||||
} |
||||
|
||||
@Override |
||||
public int getSerializationType() { |
||||
return ATOM; |
||||
} |
||||
|
||||
@Override |
||||
|
||||
public IntervalSet label() { return IntervalSet.of(label); } |
||||
|
||||
@Override |
||||
public boolean matches(int symbol, int minVocabSymbol, int maxVocabSymbol) { |
||||
return label == symbol; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return String.valueOf(label); |
||||
} |
||||
} |
@ -1,18 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
/** |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public final class BasicBlockStartState extends BlockStartState { |
||||
@Override |
||||
public int getStateType() { |
||||
return BLOCK_START; |
||||
} |
||||
} |
@ -1,20 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
/** |
||||
* |
||||
* @author Sam Harwell |
||||
*/ |
||||
public final class BasicState extends ATNState { |
||||
|
||||
@Override |
||||
public int getStateType() { |
||||
return BASIC; |
||||
} |
||||
|
||||
} |
@ -1,17 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
/** Terminal node of a simple {@code (a|b|c)} block. */ |
||||
public final class BlockEndState extends ATNState { |
||||
public BlockStartState startState; |
||||
|
||||
@Override |
||||
public int getStateType() { |
||||
return BLOCK_END; |
||||
} |
||||
} |
@ -1,12 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
/** The start of a regular {@code (...)} block. */ |
||||
public abstract class BlockStartState extends DecisionState { |
||||
public BlockEndState endState; |
||||
} |
@ -1,52 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.misc.IntervalSet; |
||||
|
||||
/** |
||||
* Utility class to create {@link AtomTransition}, {@link RangeTransition}, |
||||
* and {@link SetTransition} appropriately based on the range of the input. |
||||
* |
||||
* To keep the serialized ATN size small, we only inline atom and |
||||
* range transitions for Unicode code points <= U+FFFF. |
||||
* |
||||
* Whenever we encounter a Unicode code point > U+FFFF, we represent that |
||||
* as a set transition (even if it is logically an atom or a range). |
||||
*/ |
||||
public abstract class CodePointTransitions { |
||||
/** |
||||
* If {@code codePoint} is <= U+FFFF, returns a new {@link AtomTransition}. |
||||
* Otherwise, returns a new {@link SetTransition}. |
||||
*/ |
||||
public static Transition createWithCodePoint(ATNState target, int codePoint) { |
||||
if (Character.isSupplementaryCodePoint(codePoint)) { |
||||
return new SetTransition(target, IntervalSet.of(codePoint)); |
||||
} |
||||
else { |
||||
return new AtomTransition(target, codePoint); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* If {@code codePointFrom} and {@code codePointTo} are both |
||||
* <= U+FFFF, returns a new {@link RangeTransition}. |
||||
* Otherwise, returns a new {@link SetTransition}. |
||||
*/ |
||||
public static Transition createWithCodePointRange( |
||||
ATNState target, |
||||
int codePointFrom, |
||||
int codePointTo) { |
||||
if (Character.isSupplementaryCodePoint(codePointFrom) || |
||||
Character.isSupplementaryCodePoint(codePointTo)) { |
||||
return new SetTransition(target, IntervalSet.of(codePointFrom, codePointTo)); |
||||
} |
||||
else { |
||||
return new RangeTransition(target, codePointFrom, codePointTo); |
||||
} |
||||
} |
||||
} |
@ -1,49 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.ANTLRErrorListener; |
||||
import com.fr.third.org.antlr.v4.runtime.TokenStream; |
||||
|
||||
/** |
||||
* This class represents profiling event information for a context sensitivity. |
||||
* Context sensitivities are decisions where a particular input resulted in an |
||||
* SLL conflict, but LL prediction produced a single unique alternative. |
||||
* |
||||
* <p> |
||||
* In some cases, the unique alternative identified by LL prediction is not |
||||
* equal to the minimum represented alternative in the conflicting SLL |
||||
* configuration set. Grammars and inputs which result in this scenario are |
||||
* unable to use {@link PredictionMode#SLL}, which in turn means they cannot use |
||||
* the two-stage parsing strategy to improve parsing performance for that |
||||
* input.</p> |
||||
* |
||||
* @see ParserATNSimulator#reportContextSensitivity |
||||
* @see ANTLRErrorListener#reportContextSensitivity |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public class ContextSensitivityInfo extends DecisionEventInfo { |
||||
/** |
||||
* Constructs a new instance of the {@link ContextSensitivityInfo} class
|
||||
* with the specified detailed context sensitivity information. |
||||
* |
||||
* @param decision The decision number |
||||
* @param configs The final configuration set containing the unique |
||||
* alternative identified by full-context prediction |
||||
* @param input The input token stream |
||||
* @param startIndex The start index for the current prediction |
||||
* @param stopIndex The index at which the context sensitivity was |
||||
* identified during full-context prediction |
||||
*/ |
||||
public ContextSensitivityInfo(int decision, |
||||
ATNConfigSet configs, |
||||
TokenStream input, int startIndex, int stopIndex) |
||||
{ |
||||
super( decision, configs, input, startIndex, stopIndex, true); |
||||
} |
||||
} |
@ -1,75 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import com.fr.third.org.antlr.v4.runtime.TokenStream; |
||||
|
||||
/** |
||||
* This is the base class for gathering detailed information about prediction |
||||
* events which occur during parsing. |
||||
* |
||||
* Note that we could record the parser call stack at the time this event |
||||
* occurred but in the presence of left recursive rules, the stack is kind of |
||||
* meaningless. It's better to look at the individual configurations for their |
||||
* individual stacks. Of course that is a {@link PredictionContext} object |
||||
* not a parse tree node and so it does not have information about the extent |
||||
* (start...stop) of the various subtrees. Examining the stack tops of all |
||||
* configurations provide the return states for the rule invocations. |
||||
* From there you can get the enclosing rule. |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public class DecisionEventInfo { |
||||
/** |
||||
* The invoked decision number which this event is related to. |
||||
* |
||||
* @see ATN#decisionToState |
||||
*/ |
||||
public final int decision; |
||||
|
||||
/** |
||||
* The configuration set containing additional information relevant to the |
||||
* prediction state when the current event occurred, or {@code null} if no |
||||
* additional information is relevant or available. |
||||
*/ |
||||
public final ATNConfigSet configs; |
||||
|
||||
/** |
||||
* The input token stream which is being parsed. |
||||
*/ |
||||
public final TokenStream input; |
||||
|
||||
/** |
||||
* The token index in the input stream at which the current prediction was |
||||
* originally invoked. |
||||
*/ |
||||
public final int startIndex; |
||||
|
||||
/** |
||||
* The token index in the input stream at which the current event occurred. |
||||
*/ |
||||
public final int stopIndex; |
||||
|
||||
/** |
||||
* {@code true} if the current event occurred during LL prediction; |
||||
* otherwise, {@code false} if the input occurred during SLL prediction. |
||||
*/ |
||||
public final boolean fullCtx; |
||||
|
||||
public DecisionEventInfo(int decision, |
||||
ATNConfigSet configs, |
||||
TokenStream input, int startIndex, int stopIndex, |
||||
boolean fullCtx) |
||||
{ |
||||
this.decision = decision; |
||||
this.fullCtx = fullCtx; |
||||
this.stopIndex = stopIndex; |
||||
this.input = input; |
||||
this.startIndex = startIndex; |
||||
this.configs = configs; |
||||
} |
||||
} |
@ -1,244 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* This class contains profiling gathered for a particular decision. |
||||
* |
||||
* <p> |
||||
* Parsing performance in ANTLR 4 is heavily influenced by both static factors |
||||
* (e.g. the form of the rules in the grammar) and dynamic factors (e.g. the |
||||
* choice of input and the state of the DFA cache at the time profiling |
||||
* operations are started). For best results, gather and use aggregate |
||||
* statistics from a large sample of inputs representing the inputs expected in |
||||
* production before using the results to make changes in the grammar.</p> |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public class DecisionInfo { |
||||
/** |
||||
* The decision number, which is an index into {@link ATN#decisionToState}. |
||||
*/ |
||||
public final int decision; |
||||
|
||||
/** |
||||
* The total number of times {@link ParserATNSimulator#adaptivePredict} was |
||||
* invoked for this decision. |
||||
*/ |
||||
public long invocations; |
||||
|
||||
/** |
||||
* The total time spent in {@link ParserATNSimulator#adaptivePredict} for |
||||
* this decision, in nanoseconds. |
||||
* |
||||
* <p> |
||||
* The value of this field contains the sum of differential results obtained |
||||
* by {@link System#nanoTime()}, and is not adjusted to compensate for JIT |
||||
* and/or garbage collection overhead. For best accuracy, use a modern JVM |
||||
* implementation that provides precise results from |
||||
* {@link System#nanoTime()}, and perform profiling in a separate process |
||||
* which is warmed up by parsing the input prior to profiling. If desired, |
||||
* call {@link ATNSimulator#clearDFA} to reset the DFA cache to its initial |
||||
* state before starting the profiling measurement pass.</p> |
||||
*/ |
||||
public long timeInPrediction; |
||||
|
||||
/** |
||||
* The sum of the lookahead required for SLL prediction for this decision. |
||||
* Note that SLL prediction is used before LL prediction for performance |
||||
* reasons even when {@link PredictionMode#LL} or |
||||
* {@link PredictionMode#LL_EXACT_AMBIG_DETECTION} is used. |
||||
*/ |
||||
public long SLL_TotalLook; |
||||
|
||||
/** |
||||
* Gets the minimum lookahead required for any single SLL prediction to |
||||
* complete for this decision, by reaching a unique prediction, reaching an |
||||
* SLL conflict state, or encountering a syntax error. |
||||
*/ |
||||
public long SLL_MinLook; |
||||
|
||||
/** |
||||
* Gets the maximum lookahead required for any single SLL prediction to |
||||
* complete for this decision, by reaching a unique prediction, reaching an |
||||
* SLL conflict state, or encountering a syntax error. |
||||
*/ |
||||
public long SLL_MaxLook; |
||||
|
||||
/** |
||||
* Gets the {@link LookaheadEventInfo} associated with the event where the |
||||
* {@link #SLL_MaxLook} value was set. |
||||
*/ |
||||
public LookaheadEventInfo SLL_MaxLookEvent; |
||||
|
||||
/** |
||||
* The sum of the lookahead required for LL prediction for this decision. |
||||
* Note that LL prediction is only used when SLL prediction reaches a |
||||
* conflict state. |
||||
*/ |
||||
public long LL_TotalLook; |
||||
|
||||
/** |
||||
* Gets the minimum lookahead required for any single LL prediction to |
||||
* complete for this decision. An LL prediction completes when the algorithm |
||||
* reaches a unique prediction, a conflict state (for |
||||
* {@link PredictionMode#LL}, an ambiguity state (for |
||||
* {@link PredictionMode#LL_EXACT_AMBIG_DETECTION}, or a syntax error. |
||||
*/ |
||||
public long LL_MinLook; |
||||
|
||||
/** |
||||
* Gets the maximum lookahead required for any single LL prediction to |
||||
* complete for this decision. An LL prediction completes when the algorithm |
||||
* reaches a unique prediction, a conflict state (for |
||||
* {@link PredictionMode#LL}, an ambiguity state (for |
||||
* {@link PredictionMode#LL_EXACT_AMBIG_DETECTION}, or a syntax error. |
||||
*/ |
||||
public long LL_MaxLook; |
||||
|
||||
/** |
||||
* Gets the {@link LookaheadEventInfo} associated with the event where the |
||||
* {@link #LL_MaxLook} value was set. |
||||
*/ |
||||
public LookaheadEventInfo LL_MaxLookEvent; |
||||
|
||||
/** |
||||
* A collection of {@link ContextSensitivityInfo} instances describing the |
||||
* context sensitivities encountered during LL prediction for this decision. |
||||
* |
||||
* @see ContextSensitivityInfo |
||||
*/ |
||||
public final List<ContextSensitivityInfo> contextSensitivities = new ArrayList<ContextSensitivityInfo>(); |
||||
|
||||
/** |
||||
* A collection of {@link ErrorInfo} instances describing the parse errors |
||||
* identified during calls to {@link ParserATNSimulator#adaptivePredict} for |
||||
* this decision. |
||||
* |
||||
* @see ErrorInfo |
||||
*/ |
||||
public final List<ErrorInfo> errors = new ArrayList<ErrorInfo>(); |
||||
|
||||
/** |
||||
* A collection of {@link AmbiguityInfo} instances describing the |
||||
* ambiguities encountered during LL prediction for this decision. |
||||
* |
||||
* @see AmbiguityInfo |
||||
*/ |
||||
public final List<AmbiguityInfo> ambiguities = new ArrayList<AmbiguityInfo>(); |
||||
|
||||
/** |
||||
* A collection of {@link PredicateEvalInfo} instances describing the |
||||
* results of evaluating individual predicates during prediction for this |
||||
* decision. |
||||
* |
||||
* @see PredicateEvalInfo |
||||
*/ |
||||
public final List<PredicateEvalInfo> predicateEvals = new ArrayList<PredicateEvalInfo>(); |
||||
|
||||
/** |
||||
* The total number of ATN transitions required during SLL prediction for |
||||
* this decision. An ATN transition is determined by the number of times the |
||||
* DFA does not contain an edge that is required for prediction, resulting |
||||
* in on-the-fly computation of that edge. |
||||
* |
||||
* <p> |
||||
* If DFA caching of SLL transitions is employed by the implementation, ATN |
||||
* computation may cache the computed edge for efficient lookup during |
||||
* future parsing of this decision. Otherwise, the SLL parsing algorithm |
||||
* will use ATN transitions exclusively.</p> |
||||
* |
||||
* @see #SLL_ATNTransitions |
||||
* @see ParserATNSimulator#computeTargetState |
||||
* @see LexerATNSimulator#computeTargetState |
||||
*/ |
||||
public long SLL_ATNTransitions; |
||||
|
||||
/** |
||||
* The total number of DFA transitions required during SLL prediction for |
||||
* this decision. |
||||
* |
||||
* <p>If the ATN simulator implementation does not use DFA caching for SLL |
||||
* transitions, this value will be 0.</p> |
||||
* |
||||
* @see ParserATNSimulator#getExistingTargetState |
||||
* @see LexerATNSimulator#getExistingTargetState |
||||
*/ |
||||
public long SLL_DFATransitions; |
||||
|
||||
/** |
||||
* Gets the total number of times SLL prediction completed in a conflict |
||||
* state, resulting in fallback to LL prediction. |
||||
* |
||||
* <p>Note that this value is not related to whether or not |
||||
* {@link PredictionMode#SLL} may be used successfully with a particular |
||||
* grammar. If the ambiguity resolution algorithm applied to the SLL |
||||
* conflicts for this decision produce the same result as LL prediction for |
||||
* this decision, {@link PredictionMode#SLL} would produce the same overall |
||||
* parsing result as {@link PredictionMode#LL}.</p> |
||||
*/ |
||||
public long LL_Fallback; |
||||
|
||||
/** |
||||
* The total number of ATN transitions required during LL prediction for |
||||
* this decision. An ATN transition is determined by the number of times the |
||||
* DFA does not contain an edge that is required for prediction, resulting |
||||
* in on-the-fly computation of that edge. |
||||
* |
||||
* <p> |
||||
* If DFA caching of LL transitions is employed by the implementation, ATN |
||||
* computation may cache the computed edge for efficient lookup during |
||||
* future parsing of this decision. Otherwise, the LL parsing algorithm will |
||||
* use ATN transitions exclusively.</p> |
||||
* |
||||
* @see #LL_DFATransitions |
||||
* @see ParserATNSimulator#computeTargetState |
||||
* @see LexerATNSimulator#computeTargetState |
||||
*/ |
||||
public long LL_ATNTransitions; |
||||
|
||||
/** |
||||
* The total number of DFA transitions required during LL prediction for |
||||
* this decision. |
||||
* |
||||
* <p>If the ATN simulator implementation does not use DFA caching for LL |
||||
* transitions, this value will be 0.</p> |
||||
* |
||||
* @see ParserATNSimulator#getExistingTargetState |
||||
* @see LexerATNSimulator#getExistingTargetState |
||||
*/ |
||||
public long LL_DFATransitions; |
||||
|
||||
/** |
||||
* Constructs a new instance of the {@link DecisionInfo} class to contain |
||||
* statistics for a particular decision. |
||||
* |
||||
* @param decision The decision number |
||||
*/ |
||||
public DecisionInfo(int decision) { |
||||
this.decision = decision; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "{" + |
||||
"decision=" + decision + |
||||
", contextSensitivities=" + contextSensitivities.size() + |
||||
", errors=" + errors.size() + |
||||
", ambiguities=" + ambiguities.size() + |
||||
", SLL_lookahead=" + SLL_TotalLook + |
||||
", SLL_ATNTransitions=" + SLL_ATNTransitions + |
||||
", SLL_DFATransitions=" + SLL_DFATransitions + |
||||
", LL_Fallback=" + LL_Fallback + |
||||
", LL_lookahead=" + LL_TotalLook + |
||||
", LL_ATNTransitions=" + LL_ATNTransitions + |
||||
'}'; |
||||
} |
||||
} |
@ -1,12 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
||||
* Use of this file is governed by the BSD 3-clause license that |
||||
* can be found in the LICENSE.txt file in the project root. |
||||
*/ |
||||
|
||||
package com.fr.third.org.antlr.v4.runtime.atn; |
||||
|
||||
public abstract class DecisionState extends ATNState { |
||||
public int decision = -1; |
||||
public boolean nonGreedy; |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue