forked from jasder/antlr
* Redefine checkVersion as version mismatch detection instead of a compatibility check
* Update notification behavior to notify callback listeners instead of throwing an exception * Remove the distinction between regular and "extended" semantics
This commit is contained in:
parent
e4e1cb1845
commit
80125d661e
|
@ -33,11 +33,14 @@ package org.antlr.v4.runtime;
|
||||||
import org.antlr.v4.runtime.misc.NotNull;
|
import org.antlr.v4.runtime.misc.NotNull;
|
||||||
import org.antlr.v4.runtime.misc.Nullable;
|
import org.antlr.v4.runtime.misc.Nullable;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides access to the current version of the ANTLR 4 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
|
* library as compile-time and runtime constants, along with methods for
|
||||||
* verifying a minimum level compatibility before executing code which depends
|
* checking for matching version numbers and notifying listeners in the case
|
||||||
* on the ANTLR 4 runtime library.
|
* where a version mismatch is detected.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The runtime version information is provided by {@link #VERSION} and
|
* The runtime version information is provided by {@link #VERSION} and
|
||||||
|
@ -45,23 +48,30 @@ import org.antlr.v4.runtime.misc.Nullable;
|
||||||
* provided in the documentation for each member.</p>
|
* provided in the documentation for each member.</p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The runtime compatibility check is implemented by {@link #checkVersion}.
|
* The runtime version check is implemented by {@link #checkVersion}. Detailed
|
||||||
* Detailed information about incorporating this call into user code, as well as
|
* information about incorporating this call into user code, as well as its use
|
||||||
* its use in generated code, is provided in the documentation for the
|
* in generated code, is provided in the documentation for the method.</p>
|
||||||
* method.</p>
|
*
|
||||||
|
* <p>
|
||||||
|
* By default, the {@link ConsoleListener#INSTANCE} listener is
|
||||||
|
* automatically registered, and reports mismatched versions to
|
||||||
|
* {@link System#err}. This default listener may be removed by calling
|
||||||
|
* {@link #removeListener} or {@link #clearListeners}, and may be
|
||||||
|
* re-registered by calling {@link #addListener}.</p>
|
||||||
*/
|
*/
|
||||||
public class RuntimeMetaData {
|
public class RuntimeMetaData {
|
||||||
/**
|
/**
|
||||||
* This exception is thrown to indicate that the version of ANTLR used to
|
* This class provides detailed information about a mismatch between the
|
||||||
* generate and/or compile a parser is not compatible with the currently
|
* version of the tool a parser was generated with, the version of the
|
||||||
* executing version of the runtime library.
|
* runtime a parser was compiled against, and/or the currently executing
|
||||||
|
* version of the runtime.
|
||||||
*
|
*
|
||||||
* @see #checkVersion
|
* @see #checkVersion
|
||||||
*/
|
*/
|
||||||
public static class ANTLRVersionMismatchException extends Exception {
|
public static class VersionMismatchDetails {
|
||||||
/**
|
/**
|
||||||
* The version of the ANTLR 4 Tool a parser was generated with. This
|
* The version of the ANTLR 4 Tool a parser was generated with. This
|
||||||
* value may be {@code null} if the version check was called from
|
* value may be {@code null} if {@link #checkVersion} was called from
|
||||||
* user-defined code instead of a call automatically included in the
|
* user-defined code instead of a call automatically included in the
|
||||||
* generated parser.
|
* generated parser.
|
||||||
*/
|
*/
|
||||||
|
@ -75,41 +85,138 @@ public class RuntimeMetaData {
|
||||||
public final String compileTimeRuntimeVersion;
|
public final String compileTimeRuntimeVersion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new instance of the
|
* Constructs a new instance of the {@link VersionMismatchDetails} class
|
||||||
* {@link ANTLRVersionMismatchException} class with the specified
|
* with the specified detailed information about a mismatch between
|
||||||
* detailed information about a runtime library version compatibility
|
* ANTLR tool and runtime versions used by a parser.
|
||||||
* error.
|
|
||||||
*
|
*
|
||||||
* @param message A description of the incompatibility between the Tool
|
|
||||||
* version, the compile-time runtime version, and/or the currently
|
|
||||||
* executing runtime version
|
|
||||||
* @param generatingToolVersion The version of the ANTLR 4 Tool a parser
|
* @param generatingToolVersion The version of the ANTLR 4 Tool a parser
|
||||||
* was generated with, or {@code null} if the version check was not part
|
* was generated with, or {@code null} if the version check was not part
|
||||||
* of the automatically-generated parser code
|
* of the automatically-generated parser code
|
||||||
* @param compileTimeRuntimeVersion The version of the ANTLR 4 Runtime
|
* @param compileTimeRuntimeVersion The version of the ANTLR 4 Runtime
|
||||||
* library the code was compiled against
|
* library the code was compiled against
|
||||||
*/
|
*/
|
||||||
public ANTLRVersionMismatchException(String message, String generatingToolVersion, String compileTimeRuntimeVersion) {
|
VersionMismatchDetails(@Nullable String generatingToolVersion, @NotNull String compileTimeRuntimeVersion) {
|
||||||
super(message);
|
|
||||||
this.generatingToolVersion = generatingToolVersion;
|
this.generatingToolVersion = generatingToolVersion;
|
||||||
this.compileTimeRuntimeVersion = compileTimeRuntimeVersion;
|
this.compileTimeRuntimeVersion = compileTimeRuntimeVersion;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface defines a listener which handles notifications about
|
||||||
|
* mismatched ANTLR Tool and/or Runtime versions.
|
||||||
|
*/
|
||||||
|
public interface Listener {
|
||||||
|
/**
|
||||||
|
* Report a version mismatch which was detected by
|
||||||
|
* {@link #checkDetails}.
|
||||||
|
*
|
||||||
|
* <p>Note that if a registered listener throws an exception during the
|
||||||
|
* handling of this event, the following will be impacted:</p>
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>The lexer or parser which called {@link #checkVersion} will be
|
||||||
|
* unusable due to throwing an exception in a static initializer
|
||||||
|
* block.</li>
|
||||||
|
* <li>No additional registered listeners will be notified about the
|
||||||
|
* version mismatch.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param details a {@link VersionMismatchDetails} instance containing
|
||||||
|
* detailed information about the specific version mismatch detected
|
||||||
|
*/
|
||||||
|
void reportVersionMismatch(@NotNull VersionMismatchDetails details);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides a basic implementation of {@link Listener} which
|
||||||
|
* writes information about mismatched versions to {@link System#err}.
|
||||||
|
*/
|
||||||
|
public static class ConsoleListener implements Listener {
|
||||||
|
/**
|
||||||
|
* A default instance of {@link ConsoleListener} which is automatically
|
||||||
|
* registered to receive version mismatch events.
|
||||||
|
*/
|
||||||
|
public static final ConsoleListener INSTANCE = new ConsoleListener();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
public void reportVersionMismatch(@NotNull VersionMismatchDetails details) {
|
||||||
return super.getMessage() + ": Tool version " + generatingToolVersion + "; compile-time runtime version " + compileTimeRuntimeVersion;
|
String message;
|
||||||
|
String referenceVersion;
|
||||||
|
if (details.generatingToolVersion != null && !VERSION.equals(details.generatingToolVersion)) {
|
||||||
|
referenceVersion = details.generatingToolVersion;
|
||||||
|
message = "ANTLR Tool version %s used for code generation does not match the current runtime version %s";
|
||||||
|
}
|
||||||
|
else if (!VERSION.equals(details.compileTimeRuntimeVersion)) {
|
||||||
|
referenceVersion = details.compileTimeRuntimeVersion;
|
||||||
|
message = "ANTLR Runtime version %s used for parser compilation does not match the current runtime version %s";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
referenceVersion = "";
|
||||||
|
message = "The ANTLR Runtime reported a version mismatch against the current runtime version %s%s";
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatted = String.format(message, referenceVersion, VERSION);
|
||||||
|
System.err.println(formatted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of listeners registered to receive notifications of mismatched
|
||||||
|
* ANTLR versions.
|
||||||
|
*/
|
||||||
|
private static final Collection<Listener> listeners = new CopyOnWriteArraySet<Listener>();
|
||||||
|
static {
|
||||||
|
listeners.add(ConsoleListener.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a listener to receive notifications of mismatched ANTLR
|
||||||
|
* versions.
|
||||||
|
*
|
||||||
|
* @param listener the listener to notify if mismatched ANTLR versions are
|
||||||
|
* detected
|
||||||
|
*
|
||||||
|
* @see #checkVersion
|
||||||
|
*/
|
||||||
|
public static void addListener(@NotNull Listener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a specific listener registered to receive notifications of
|
||||||
|
* mismatched ANTLR versions.
|
||||||
|
*
|
||||||
|
* @param listener the listener to remove
|
||||||
|
* @return {@code true} if the listener was removed; otherwise,
|
||||||
|
* {@code false} if the specified listener was not found in the list of
|
||||||
|
* registered listeners
|
||||||
|
*/
|
||||||
|
public static boolean removeListener(@NotNull Listener listener) {
|
||||||
|
return listeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all listeners registered to receive notifications of mismatched
|
||||||
|
* ANTLR versions.
|
||||||
|
*/
|
||||||
|
public static void clearListeners() {
|
||||||
|
listeners.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A compile-time constant containing the current version of the ANTLR 4
|
* A compile-time constant containing the current version of the ANTLR 4
|
||||||
* runtime library.
|
* runtime library.
|
||||||
*
|
*
|
||||||
* <p>This compile-time constant value allows generated parsers and other
|
* <p>
|
||||||
|
* This compile-time constant value allows generated parsers and other
|
||||||
* libraries to include a literal reference to the version of the ANTLR 4
|
* libraries to include a literal reference to the version of the ANTLR 4
|
||||||
* runtime library the code was compiled against.</p>
|
* runtime library the code was compiled against.</p>
|
||||||
*
|
*
|
||||||
* <p>During development (between releases), this value contains the
|
* <p>
|
||||||
|
* During development (between releases), this value contains the
|
||||||
* <em>expected</em> next release version. For official releases, the value
|
* <em>expected</em> next release version. For official releases, the value
|
||||||
* will be the actual published version of the library.</p>
|
* will be the actual published version of the library.</p>
|
||||||
*/
|
*/
|
||||||
|
@ -118,7 +225,8 @@ public class RuntimeMetaData {
|
||||||
/**
|
/**
|
||||||
* Gets the currently executing version of the ANTLR 4 runtime library.
|
* Gets the currently executing version of the ANTLR 4 runtime library.
|
||||||
*
|
*
|
||||||
* <p>This method provides runtime access to the {@link #VERSION} field, as
|
* <p>
|
||||||
|
* This method provides runtime access to the {@link #VERSION} field, as
|
||||||
* opposed to directly referencing the field as a compile-time constant.</p>
|
* opposed to directly referencing the field as a compile-time constant.</p>
|
||||||
*
|
*
|
||||||
* @return The currently executing version of the ANTLR 4 library
|
* @return The currently executing version of the ANTLR 4 library
|
||||||
|
@ -129,59 +237,44 @@ public class RuntimeMetaData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method provides the ability to verify that the version of the ANTLR
|
* This method provides the ability to detect mismatches between the version
|
||||||
* 4 used to execute a parser is compatible with the Tool used to generate
|
* of ANTLR 4 used to generate a parser, the version of the ANTLR runtime a
|
||||||
* the parser code and/or the version of the runtime the parser was compiled
|
* parser was compiled against, and the version of the ANTLR runtime which
|
||||||
* against.
|
* is currently executing.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Starting with ANTLR 4.2.3, the code generator emits two constants in each
|
* Starting with ANTLR 4.2.3, the code generator emits a call to this method
|
||||||
* generated parser: a hard-coded constant indicating the version of the
|
* using two constants in each generated lexer and parser: a hard-coded
|
||||||
* tool used to generate the parser and a reference to the compile-time
|
* constant indicating the version of the tool used to generate the parser
|
||||||
* constant {@link #VERSION}. At runtime, this method is called to ensure
|
* and a reference to the compile-time constant {@link #VERSION}. At
|
||||||
* that, according to the version numbers, the semantics of the generated
|
* runtime, this method is called during the initialization of the generated
|
||||||
* code are known to be compatible with the version of the ANTLR runtime
|
* parser to detect mismatched versions, and notify the registered listeners
|
||||||
* used to execute code.</p>
|
* prior to creating instances of the parser.</p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The definition of "semantic changes" which are considered by this method
|
* This method does not perform any detection or filtering of semantic
|
||||||
* depend on the value of {@code extendedSemantics}. When this value is
|
* changes between tool and runtime versions. It simply checks for a simple
|
||||||
* {@code false}, as is the case for calls to this method in generated code,
|
* version match and notifies the registered listeners any time a difference
|
||||||
* "semantic changes" means changes in the runtime that alter the behavior
|
* is detected.</p>
|
||||||
* of parsers that use only standardized language features, which does not
|
|
||||||
* include the behavior of target-language-specific features such as
|
|
||||||
* embedded actions, custom semantic predicates, and runtime methods that
|
|
||||||
* are never called by the generated code but may be overridden in separate
|
|
||||||
* user code. When this value is {@code true}, "semantic changes" indicates
|
|
||||||
* a wider check across frequently used aspects of the runtime. The latter
|
|
||||||
* case may or may not consider all breaking changes across releases; for
|
|
||||||
* details on the specific methods in place see the release notes for the
|
|
||||||
* affected version(s).</p>
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Note that if this method throws an exception when
|
* Note that some breaking changes between releases could result in other
|
||||||
* {@code extendedSemantics} is {@code false}, the lexer or parser which
|
* types of runtime exceptions, such as a {@link LinkageError}, prior to
|
||||||
* resulted in the exception will be prevented from executing, so this
|
* calling this method. In these cases, the underlying version mismatch will
|
||||||
* behavior is reserved for changes that are true breaking changes in the
|
* not be reported to the listeners. This method is primarily intended to
|
||||||
* behavior. These changes, if any, are mentioned in the release notes for
|
* notify users of potential semantic changes between releases that do not
|
||||||
* the affected release.</p>
|
* result in binary compatibility problems which would be detected by the
|
||||||
|
* class loader. As with semantic changes, changes which break binary
|
||||||
|
* compatibility between releases are mentioned in the release notes
|
||||||
|
* accompanying the affected release.</p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Also note that some breaking changes between releases could result in
|
* <strong>Additional note for target developers:</strong> The version check
|
||||||
* other types of runtime exceptions, such as a {@link LinkageError}, prior
|
* implemented by this class is designed to address specific compatibility
|
||||||
* to calling this method. This method is primarily intended to catch
|
* concerns that may arise during the execution of Java applications. Other
|
||||||
* semantic changes that do not result in binary compatibility problems
|
* targets should consider the implementation of this method in the context
|
||||||
* which would be detected by the class loader. As with semantic changes,
|
* of that target's known execution environment, which may or may not
|
||||||
* changes which break binary compatibility between releases are mentioned
|
* resemble the design provided for the Java target.</p>
|
||||||
* in the release notes accompanying the affected release.</p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* <strong>Additional note for target developers:</strong> The compatibility
|
|
||||||
* check implemented by this class is designed to address specific
|
|
||||||
* compatibility issues 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 toolVersion The version of the tool used to generate a parser.
|
* @param toolVersion The version of the tool used to generate a parser.
|
||||||
* This value may be null when called from user code that was not generated
|
* This value may be null when called from user code that was not generated
|
||||||
|
@ -189,26 +282,21 @@ public class RuntimeMetaData {
|
||||||
* @param compileTimeVersion The version of the runtime the parser was
|
* @param compileTimeVersion The version of the runtime the parser was
|
||||||
* compiled against. This should always be passed using a direct reference
|
* compiled against. This should always be passed using a direct reference
|
||||||
* to {@link #VERSION}.
|
* to {@link #VERSION}.
|
||||||
* @param extendedSemantics {@code false} to only check compatibility for
|
|
||||||
* the API used in generated code, not counting embedded actions and
|
|
||||||
* semantic predicates; otherwise, {@code true} to check compatibility
|
|
||||||
* across a wider range of frequently-used features that are commonly used
|
|
||||||
* in user-defined embedded actions and/or semantic predicates.
|
|
||||||
*
|
|
||||||
* @exception ANTLRVersionMismatchException if the version of the ANTLR
|
|
||||||
* runtime used to execute a compiled parser contains semantic changes which
|
|
||||||
* would alter the behavior of the generated code
|
|
||||||
*/
|
*/
|
||||||
public static void checkVersion(@Nullable String toolVersion, @NotNull String compileTimeVersion, boolean extendedSemantics) throws ANTLRVersionMismatchException {
|
public static void checkVersion(@Nullable String toolVersion, @NotNull String compileTimeVersion) {
|
||||||
/* Currently there are no versions of the ANTLR runtime library which
|
boolean report = false;
|
||||||
* are incompatible with respect to this method.
|
if (toolVersion != null && !VERSION.equals(toolVersion)) {
|
||||||
*
|
report = true;
|
||||||
* * Prior to ANTLR 4.2.3, the ANTLR tool did not emit calls to this
|
}
|
||||||
* method in the generated code, and did not expose the VERSION
|
else if (!VERSION.equals(compileTimeVersion)) {
|
||||||
* field. For the specific purposes of this compatibility check, the
|
report = true;
|
||||||
* "first public release" of ANTLR 4 can be treated as 4.2.3.
|
}
|
||||||
* * If an incompatibility is introduced in a version after 4.2.3,
|
|
||||||
* specific handling for the affected versions can be added.
|
if (report) {
|
||||||
*/
|
VersionMismatchDetails details = new VersionMismatchDetails(toolVersion, compileTimeVersion);
|
||||||
|
for (Listener listener : listeners) {
|
||||||
|
listener.reportVersionMismatch(details);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,14 +214,7 @@ Parser(parser, funcs, atn, sempredFuncs, superClass) ::= <<
|
||||||
Parser_(parser, funcs, atn, sempredFuncs, ctor, superClass) ::= <<
|
Parser_(parser, funcs, atn, sempredFuncs, ctor, superClass) ::= <<
|
||||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
||||||
public class <parser.name> extends <superClass> {
|
public class <parser.name> extends <superClass> {
|
||||||
static {
|
static { RuntimeMetaData.checkVersion("<file.ANTLRVersion>", RuntimeMetaData.VERSION); }
|
||||||
try {
|
|
||||||
RuntimeMetaData.checkVersion("<file.ANTLRVersion>", RuntimeMetaData.VERSION, false);
|
|
||||||
}
|
|
||||||
catch (RuntimeMetaData.ANTLRVersionMismatchException ex) {
|
|
||||||
throw new ExceptionInInitializerError(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static final DFA[] _decisionToDFA;
|
protected static final DFA[] _decisionToDFA;
|
||||||
protected static final PredictionContextCache _sharedContextCache =
|
protected static final PredictionContextCache _sharedContextCache =
|
||||||
|
@ -857,14 +850,7 @@ import org.antlr.v4.runtime.misc.*;
|
||||||
Lexer(lexer, atn, actionFuncs, sempredFuncs, superClass) ::= <<
|
Lexer(lexer, atn, actionFuncs, sempredFuncs, superClass) ::= <<
|
||||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
||||||
public class <lexer.name> extends <superClass> {
|
public class <lexer.name> extends <superClass> {
|
||||||
static {
|
static { RuntimeMetaData.checkVersion("<lexerFile.ANTLRVersion>", RuntimeMetaData.VERSION); }
|
||||||
try {
|
|
||||||
RuntimeMetaData.checkVersion("<lexerFile.ANTLRVersion>", RuntimeMetaData.VERSION, false);
|
|
||||||
}
|
|
||||||
catch (RuntimeMetaData.ANTLRVersionMismatchException ex) {
|
|
||||||
throw new ExceptionInInitializerError(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static final DFA[] _decisionToDFA;
|
protected static final DFA[] _decisionToDFA;
|
||||||
protected static final PredictionContextCache _sharedContextCache =
|
protected static final PredictionContextCache _sharedContextCache =
|
||||||
|
|
Loading…
Reference in New Issue