1<?php 2 3declare(strict_types=1); 4 5namespace Antlr\Antlr4\Runtime; 6 7/** 8 * This class provides access to the current version of the ANTLR 4 runtime 9 * library as compile-time and runtime constants, along with methods for 10 * checking for matching version numbers and notifying listeners in the case 11 * where a version mismatch is detected. 12 * 13 * The runtime version information is provided by {@see RuntimeMetaData::VERSION} and 14 * {@see RuntimeMetaData::getRuntimeVersion()}. Detailed information about these values is 15 * provided in the documentation for each member. 16 * 17 * The runtime version check is implemented by {@see RuntimeMetaData::checkVersion()}. Detailed 18 * information about incorporating this call into user code, as well as its use 19 * in generated code, is provided in the documentation for the method.</p> 20 * 21 * Version strings x.y and x.y.z are considered "compatible" and no error 22 * would be generated. Likewise, version strings x.y-SNAPSHOT and x.y.z are 23 * considered "compatible" because the major and minor components x.y 24 * are the same in each. 25 * 26 * @since 4.3 27 */ 28final class RuntimeMetaData 29{ 30 /** 31 * A compile-time constant containing the current version of the ANTLR 4 32 * runtime library. 33 * 34 * This compile-time constant value allows generated parsers and other 35 * libraries to include a literal reference to the version of the ANTLR 4 36 * runtime library the code was compiled against. At each release, we 37 * change this value. 38 * 39 * Version numbers are assumed to have the form 40 * `major.minor.patch.evision-suffix`, with the individual components 41 * defined as follows. 42 * 43 * - major is a required non-negative integer, and is equal to 44 * `4 for ANTLR 4. 45 * - minor< is a required non-negative integer. 46 * - patch is an optional non-negative integer. When `patch` is omitted, 47 * the `.` (dot) appearing before it is also omitted. 48 * - revision is an optional non-negative integer, and may only be included 49 * when `patch` is also included. When `revision` is omitted, the `.` (dot) 50 * appearing before it is also omitted. 51 * - suffix is an optional string. When `suffix` is omitted, the `-` 52 * (hyphen-minus) appearing before it is also omitted. 53 */ 54 public const VERSION = '4.9.2'; 55 56 /** 57 * Gets the currently executing version of the ANTLR 4 runtime library. 58 * 59 * This method provides runtime access to the 60 * {@see RuntimeMetaData::VERSION} field, as opposed to directly 61 * referencing the field as a compile-time constant.</p> 62 * 63 * @return string The currently executing version of the ANTLR 4 library 64 */ 65 public static function getRuntimeVersion() : string 66 { 67 return self::VERSION; 68 } 69 70 /** 71 * This method provides the ability to detect mismatches between the version 72 * of ANTLR 4 used to generate a parser, the version of the ANTLR runtime a 73 * parser was compiled against, and the version of the ANTLR runtime which 74 * is currently executing. 75 * 76 * The version check is designed to detect the following two specific 77 * scenarios. 78 * 79 * The ANTLR Tool version used for code generation does not match the 80 * currently executing runtime version. 81 * The ANTLR Runtime version referenced at the time a parser was 82 * compiled does not match the currently executing runtime version. 83 * 84 * Starting with ANTLR 4.3, the code generator emits a call to this method 85 * using two constants in each generated lexer and parser: a hard-coded 86 * constant indicating the version of the tool used to generate the parser 87 * and a reference to the compile-time constant {@link VERSION}. At 88 * runtime, this method is called during the initialization of the generated 89 * parser to detect mismatched versions, and notify the registered listeners 90 * prior to creating instances of the parser. 91 * 92 * This method does not perform any detection or filtering of semantic 93 * changes between tool and runtime versions. It simply checks for a 94 * version match and emits an error to stderr if a difference 95 * is detected. 96 * 97 * Note that some breaking changes between releases could result in other 98 * types of runtime exceptions, prior to calling this method. In these 99 * cases, the underlying version mismatch will not be reported here. 100 * This method is primarily intended to notify users of potential 101 * semantic changes between releases that do not result in binary 102 * compatibility problems which would be detected by the class loader. 103 * As with semantic changes, changes that break binary compatibility 104 * between releases are mentioned in the release notes accompanying 105 * the affected release. 106 * 107 * *Additional note for target developers:* The version check 108 * implemented by this class is designed to address specific compatibility 109 * concerns that may arise during the execution of Java applications. Other 110 * targets should consider the implementation of this method in the context 111 * of that target's known execution environment, which may or may not 112 * resemble the design provided for the Java target. 113 * 114 * @param string $generatingToolVersion The version of the tool used to 115 * generate a parser. This value may 116 * be null when called from user code 117 * that was not generated by, and does 118 * not reference, the ANTLR 4 Tool itself. 119 * @param string $compileTimeVersion The version of the runtime the parser 120 * was compiled against. This should 121 * always be passed using a direct reference 122 * to {@see RuntimeMetaData::VERSION}. 123 */ 124 public static function checkVersion(string $generatingToolVersion, string $compileTimeVersion) : void 125 { 126 $runtimeConflictsWithGeneratingTool = $generatingToolVersion !== self::VERSION 127 && self::getMajorMinorVersion($generatingToolVersion) !== self::getMajorMinorVersion(self::VERSION); 128 129 $runtimeConflictsWithCompileTimeTool = $compileTimeVersion !== self::VERSION 130 && self::getMajorMinorVersion($compileTimeVersion) !== self::getMajorMinorVersion(self::VERSION); 131 132 if ($runtimeConflictsWithGeneratingTool) { 133 \trigger_error( 134 \sprintf( 135 'ANTLR Tool version %s used for code generation does not ' . 136 'match the current runtime version %s', 137 $generatingToolVersion, 138 self::VERSION 139 ), 140 \E_USER_WARNING 141 ); 142 } 143 144 if ($runtimeConflictsWithCompileTimeTool) { 145 \trigger_error( 146 \sprintf( 147 'ANTLR Runtime version %s used for parser compilation does not ' . 148 'match the current runtime version %s', 149 $compileTimeVersion, 150 self::VERSION 151 ), 152 \E_USER_WARNING 153 ); 154 } 155 } 156 157 /** 158 * Gets the major and minor version numbers from a version string. For 159 * details about the syntax of the input `version`. 160 * E.g., from x.y.z return x.y. 161 * 162 * @param string $version The complete version string. 163 * 164 * @return string A string of the form `major`.`minor` containing 165 * only the major and minor components of the version string. 166 */ 167 public static function getMajorMinorVersion(string $version) : string 168 { 169 $firstDot = \strpos($version, '.'); 170 $referenceLength = \strlen($version); 171 $secondDot = false; 172 173 if ($firstDot >= 0 && $firstDot < $referenceLength) { 174 $secondDot = \strpos($version, '.', $firstDot + 1); 175 } 176 177 $firstDash = \strpos($version, '-'); 178 179 if ($secondDot !== false) { 180 $referenceLength = \min($secondDot, $secondDot); 181 } 182 183 if ($firstDash !== false) { 184 $referenceLength = \min($referenceLength, $firstDash); 185 } 186 187 return \substr($version, 0, $referenceLength); 188 } 189} 190