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