1 /*
2 * Copyright (c) 2012-2020 The ANTLR Project. All rights reserved.
3 * Use of this file is governed by the BSD 3-clause license that
4 * can be found in the LICENSE.txt file in the project root.
5 */6 7 moduleantlr.v4.runtime.RuntimeMetaData;
8 9 importstd.algorithm : min;
10 importstd.stdio : stderr;
11 importstd..string : indexOf;
12 13 /**
14 * This class provides access to the current version of the ANTLR 4 runtime
15 * library as compile-time and runtime constants, along with methods for
16 * checking for matching version numbers and notifying listeners in the case
17 * where a version mismatch is detected.
18 *
19 * <p>
20 * The runtime version information is provided by {@link #VERSION} and
21 * {@link #getRuntimeVersion()}. Detailed information about these values is
22 * provided in the documentation for each member.</p>
23 *
24 * <p>
25 * The runtime version check is implemented by {@link #checkVersion}. Detailed
26 * information about incorporating this call into user code, as well as its use
27 * in generated code, is provided in the documentation for the method.</p>
28 *
29 * <p>
30 * Version strings x.y and x.y.z are considered "compatible" and no error
31 * would be generated. Likewise, version strings x.y-SNAPSHOT and x.y.z are
32 * considered "compatible" because the major and minor components x.y
33 * are the same in each.</p>
34 *
35 * <p>
36 * To trap any error messages issued by this code, use System.setErr()
37 * in your main() startup code.
38 * </p>
39 */40 classRuntimeMetaData41 {
42 enumstringVERSION = "4.9.2";
43 44 /**
45 * This method provides the ability to detect mismatches between the version
46 * of ANTLR 4 used to generate a parser, the version of the ANTLR runtime a
47 * parser was compiled against, and the version of the ANTLR runtime which
48 * is currently executing.
49 *
50 * <p>
51 * The version check is designed to detect the following two specific
52 * scenarios.</p>
53 *
54 * <ul>
55 * <li>The ANTLR Tool version used for code generation does not match the
56 * currently executing runtime version.</li>
57 * <li>The ANTLR Runtime version referenced at the time a parser was
58 * compiled does not match the currently executing runtime version.</li>
59 * </ul>
60 *
61 * <p>
62 * Starting with ANTLR 4.3, the code generator emits a call to this method
63 * using two constants in each generated lexer and parser: a hard-coded
64 * constant indicating the version of the tool used to generate the parser
65 * and a reference to the compile-time constant {@link #VERSION}. At
66 * runtime, this method is called during the initialization of the generated
67 * parser to detect mismatched versions, and notify the registered listeners
68 * prior to creating instances of the parser.</p>
69 *
70 * <p>
71 * This method does not perform any detection or filtering of semantic
72 * changes between tool and runtime versions. It simply checks for a
73 * version match and emits an error to stderr if a difference
74 * is detected.</p>
75 *
76 * <p>
77 * Note that some breaking changes between releases could result in other
78 * types of runtime exceptions, such as a {@link LinkageError}, prior to
79 * calling this method. In these cases, the underlying version mismatch will
80 * not be reported here. This method is primarily intended to
81 * notify users of potential semantic changes between releases that do not
82 * result in binary compatibility problems which would be detected by the
83 * class loader. As with semantic changes, changes that break binary
84 * compatibility between releases are mentioned in the release notes
85 * accompanying the affected release.</p>
86 *
87 * <p>
88 * <strong>Additional note for target developers:</strong> The version check
89 * implemented by this class is designed to address specific compatibility
90 * concerns that may arise during the execution of Java applications. Other
91 * targets should consider the implementation of this method in the context
92 * of that target's known execution environment, which may or may not
93 * resemble the design provided for the Java target.</p>
94 *
95 * @param generatingToolVersion The version of the tool used to generate a parser.
96 * This value may be null when called from user code that was not generated
97 * by, and does not reference, the ANTLR 4 Tool itself.
98 * @param compileTimeVersion The version of the runtime the parser was
99 * compiled against. This should always be passed using a direct reference
100 * to {@link #VERSION}.
101 */102 publicstaticvoidcheckVersion(stringgeneratingToolVersion, stringcompileTimeVersion)
103 {
104 stringruntimeVersion = VERSION;
105 boolruntimeConflictsWithGeneratingTool = false;
106 boolruntimeConflictsWithCompileTimeTool = false;
107 108 if (generatingToolVersion) {
109 runtimeConflictsWithGeneratingTool =
110 (runtimeVersion != generatingToolVersion) &&
111 (getMajorMinorVersion(runtimeVersion) != getMajorMinorVersion(generatingToolVersion));
112 }
113 114 runtimeConflictsWithCompileTimeTool =
115 (runtimeVersion != compileTimeVersion) &&
116 (getMajorMinorVersion(runtimeVersion) != getMajorMinorVersion(compileTimeVersion));
117 118 if (runtimeConflictsWithGeneratingTool) {
119 stderr.writefln("ANTLR Tool version %s used for code generation does not match the current runtime version %s",
120 generatingToolVersion, runtimeVersion);
121 }
122 if ( runtimeConflictsWithCompileTimeTool ) {
123 stderr.writefln("ANTLR Runtime version %s used for parser compilation does not match the current runtime version %s",
124 compileTimeVersion, runtimeVersion);
125 }
126 127 }
128 129 /**
130 * Gets the major and minor version numbers from a version string. For
131 * details about the syntax of the input {@code version}.
132 * E.g., from x.y.z return x.y.
133 *
134 * @param version The complete version string.
135 * @return A string of the form <em>major</em>.<em>minor</em> containing
136 * only the major and minor components of the version string.
137 */138 publicstaticstringgetMajorMinorVersion(stringantlr_version)
139 {
140 size_tfirstDot = antlr_version.indexOf('.');
141 size_tsecondDot = firstDot >= 0 ? antlr_version.indexOf('.', firstDot + 1) : -1;
142 size_tfirstDash = antlr_version.indexOf('-');
143 size_treferenceLength = antlr_version.length;
144 if (secondDot >= 0) {
145 referenceLength = min(referenceLength, secondDot);
146 }
147 148 if (firstDash >= 0) {
149 referenceLength = min(referenceLength, firstDash);
150 }
151 152 returnantlr_version[0..referenceLength];
153 }
154 }
155 156 version (AntlrUnittest)
157 {
158 159 importdshould;
160 161 @("compareMetaDataVersion")
162 unittest163 {
164 RuntimeMetaData.getMajorMinorVersion(RuntimeMetaData.VERSION).should.equal("4.9");
165 RuntimeMetaData.checkVersion("4.9", "4.9.2");
166 }
167 }