xref: /plugin/combo/vendor/antlr/antlr4-php-runtime/src/RuntimeMetaData.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
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